From: Guillaume Desmottes Date: Fri, 24 Apr 2009 15:28:22 +0000 (+0100) Subject: Merge branch 'master' into tp-tube X-Git-Url: https://git.0d.be/?p=empathy.git;a=commitdiff_plain;h=f02d96379cb7043611d093921755d699e48689bb;hp=c8d23985b7754541cab512992294c19f5c87cfaa Merge branch 'master' into tp-tube --- diff --git a/HACKING b/HACKING new file mode 100644 index 00000000..778244f1 --- /dev/null +++ b/HACKING @@ -0,0 +1,2 @@ +See http://live.gnome.org/Empathy/ about coding style conventions. +See also http://live.gnome.org/Empathy/Git to read about our git workflow. diff --git a/configure.ac b/configure.ac index c3926fdb..0ff17396 100644 --- a/configure.ac +++ b/configure.ac @@ -29,7 +29,7 @@ GLIB_REQUIRED=2.16.0 GTK_REQUIRED=2.16.0 GCONF_REQUIRED=1.2.0 LIBPANELAPPLET_REQUIRED=2.10.0 -TELEPATHY_GLIB_REQUIRED=0.7.23 +TELEPATHY_GLIB_REQUIRED=0.7.27 MISSION_CONTROL_REQUIRED=4.61 ENCHANT_REQUIRED=1.2.0 ISO_CODES_REQUIRED=0.35 diff --git a/docs/libempathy-gtk/libempathy-gtk-docs.sgml b/docs/libempathy-gtk/libempathy-gtk-docs.sgml index 033ebf01..f265de20 100644 --- a/docs/libempathy-gtk/libempathy-gtk-docs.sgml +++ b/docs/libempathy-gtk/libempathy-gtk-docs.sgml @@ -45,7 +45,6 @@ - diff --git a/docs/libempathy/libempathy-docs.sgml b/docs/libempathy/libempathy-docs.sgml index a7e3df9b..f3291f77 100644 --- a/docs/libempathy/libempathy-docs.sgml +++ b/docs/libempathy/libempathy-docs.sgml @@ -21,7 +21,6 @@ - @@ -45,7 +44,6 @@ - diff --git a/docs/libempathy/libempathy.types b/docs/libempathy/libempathy.types index 1a81ac67..26040474 100644 --- a/docs/libempathy/libempathy.types +++ b/docs/libempathy/libempathy.types @@ -3,7 +3,6 @@ empathy_call_factory_get_type empathy_call_handler_get_type empathy_chatroom_get_type empathy_chatroom_manager_get_type -empathy_contact_factory_get_type empathy_contact_get_type empathy_avatar_get_type empathy_contact_list_get_type @@ -12,7 +11,6 @@ empathy_contact_monitor_get_type empathy_dispatcher_get_type empathy_dispatch_operation_get_type empathy_capabilities_get_type -empathy_contact_ready_get_type empathy_debug_flags_get_type empathy_dispatch_operation_state_get_type empathy_tp_call_status_get_type @@ -29,7 +27,6 @@ empathy_tp_chat_get_type empathy_tp_contact_factory_get_type empathy_tp_contact_list_get_type empathy_tp_file_get_type -empathy_tp_group_get_type empathy_tp_roomlist_get_type empathy_tp_tube_get_type empathy_tube_handler_get_type diff --git a/empathy.doap b/empathy.doap index 7b5e7564..acd6494b 100644 --- a/empathy.doap +++ b/empathy.doap @@ -6,6 +6,7 @@ xmlns="http://usefulinc.com/ns/doap#"> Empathy Instant Messenger Send and receive instant messages + diff --git a/help/es/es.po b/help/es/es.po index da48d125..8357dde9 100644 --- a/help/es/es.po +++ b/help/es/es.po @@ -3,8 +3,8 @@ msgid "" msgstr "" "Project-Id-Version: empathy.help.HEAD\n" -"POT-Creation-Date: 2009-03-10 20:40+0000\n" -"PO-Revision-Date: 2009-03-22 16:23+0100\n" +"POT-Creation-Date: 2009-04-18 18:34+0000\n" +"PO-Revision-Date: 2009-04-21 21:04+0200\n" "Last-Translator: Jorge González \n" "Language-Team: Español \n" "MIME-Version: 1.0\n" @@ -15,7 +15,7 @@ msgstr "" #. When image changes, this message will be marked fuzzy or untranslated for you. #. It doesn't matter what you translate it to: it's not used at all. -#: C/empathy.xml:238(None) +#: C/empathy.xml:237(None) msgid "" "@@image: 'figures/empathy-main-window.png'; " "md5=38259a866f38ff1f754828e46d2b0e5c" @@ -199,37 +199,42 @@ msgid "Feedback" msgstr "Comentarios" #: C/empathy.xml:111(para) +#| msgid "" +#| "To report a bug or make a suggestion regarding the Empathy application or this manual, follow the directions in the " +#| "GNOME Feedback Page." msgid "" "To report a bug or make a suggestion regarding the Empathy application or this manual, follow the directions in the GNOME Feedback Page." +"url=\"ghelp:user-guide?feedback\" type=\"help\">GNOME Feedback Page." msgstr "" "Para informar de un fallo, o hacer alguna sugerencia concerniente a la " "aplicación Empathy o este manual, siga las " -"indicaciones en la Página " -"de comentarios de GNOME." +"indicaciones en la Página de comentarios de GNOME." -#: C/empathy.xml:119(para) +#: C/empathy.xml:118(para) msgid "Empathy is an application for instant messaging." msgstr "Empathy es una aplicación para mensajería instantánea." -#: C/empathy.xml:127(primary) C/empathy.xml:0(application) +#: C/empathy.xml:126(primary) C/empathy.xml:0(application) msgid "Empathy" msgstr "Empathy" -#: C/empathy.xml:130(primary) +#: C/empathy.xml:129(primary) msgid "empathy" msgstr "empathy" -#: C/empathy.xml:131(secondary) +#: C/empathy.xml:130(secondary) msgid "istant messaging" msgstr "mensajería instantánea" -#: C/empathy.xml:135(title) +#: C/empathy.xml:134(title) msgid "Introduction" msgstr "Introducción" -#: C/empathy.xml:136(para) +#: C/empathy.xml:135(para) msgid "" "Empathy is a multi-protocol instant messaging " "program for the GNOME Desktop. With Empathy you " @@ -241,47 +246,47 @@ msgstr "" "application> puede mantenerse en contacto con sus amigos a través de muchos " "de los servicios de mensajería instantánea soportados." -#: C/empathy.xml:146(acronym) +#: C/empathy.xml:145(acronym) msgid "AIM" msgstr "AIM" -#: C/empathy.xml:150(para) +#: C/empathy.xml:149(para) msgid "Google Talk" msgstr "Google Talk" -#: C/empathy.xml:155(para) C/empathy.xml:1090(title) +#: C/empathy.xml:154(para) C/empathy.xml:1089(title) msgid "ICQ" msgstr "ICQ" -#: C/empathy.xml:161(acronym) +#: C/empathy.xml:160(acronym) msgid "IRC" msgstr "IRC" -#: C/empathy.xml:165(para) +#: C/empathy.xml:164(para) msgid "Jabber (or XMPP)" msgstr "Jabber (o XMPP)" -#: C/empathy.xml:171(acronym) +#: C/empathy.xml:170(acronym) msgid "MSN" msgstr "MSN" -#: C/empathy.xml:175(para) C/empathy.xml:442(para) C/empathy.xml:1050(title) +#: C/empathy.xml:174(para) C/empathy.xml:441(para) C/empathy.xml:1049(title) msgid "Salut" msgstr "Salut" -#: C/empathy.xml:181(acronym) +#: C/empathy.xml:180(acronym) msgid "SIP" msgstr "SIP" -#: C/empathy.xml:185(para) C/empathy.xml:920(title) +#: C/empathy.xml:184(para) C/empathy.xml:919(title) msgid "Yahoo" msgstr "Yahoo" -#: C/empathy.xml:190(para) +#: C/empathy.xml:189(para) msgid "And many others..." msgstr "Y muchos otros…" -#: C/empathy.xml:141(para) +#: C/empathy.xml:140(para) msgid "" "Empathy supports the following services: " "" @@ -289,24 +294,24 @@ msgstr "" "Empathy soporta los siguientes servicios: " "" -#: C/empathy.xml:199(title) +#: C/empathy.xml:198(title) msgid "Getting Started" msgstr "Inicio" -#: C/empathy.xml:202(title) +#: C/empathy.xml:201(title) msgid "Starting Empathy" msgstr "Iniciar Empathy" -#: C/empathy.xml:203(para) +#: C/empathy.xml:202(para) msgid "You can start Empathy in the following ways:" msgstr "" "Puede iniciar Empathy de las siguientes formas:" -#: C/empathy.xml:207(term) +#: C/empathy.xml:206(term) msgid "Applications menu" msgstr "Menú Aplicaciones" -#: C/empathy.xml:209(para) +#: C/empathy.xml:208(para) msgid "" "Choose InternetEmpathy " "Instant Messenger." @@ -314,23 +319,23 @@ msgstr "" "Elija InternetMensajería " "instantánea Empathy." -#: C/empathy.xml:218(term) +#: C/empathy.xml:217(term) msgid "Command line" msgstr "Línea de comandos" -#: C/empathy.xml:220(para) +#: C/empathy.xml:219(para) msgid "Type empathy and then press Enter." msgstr "Escriba empathy y pulse intro." -#: C/empathy.xml:229(title) +#: C/empathy.xml:228(title) msgid "When You Start Empathy" msgstr "Al iniciar Empathy" -#: C/empathy.xml:234(title) +#: C/empathy.xml:233(title) msgid "Empathy Main Window" msgstr "Ventana principal de Empathy" -#: C/empathy.xml:241(phrase) +#: C/empathy.xml:240(phrase) msgid "" "Shows main window. Contains the titlebar, the menubar, " "contact list, status icon and status arrow button list." @@ -339,7 +344,7 @@ msgstr "" "título, la barra de menú, la lista de contactos, el icono de estado y la " "lista de estados." -#: C/empathy.xml:230(para) +#: C/empathy.xml:229(para) msgid "" "When you start Empathy the following window is " "shown. " @@ -347,54 +352,54 @@ msgstr "" "Se mostrará la siguiente ventana al iniciar Empathy. " -#: C/empathy.xml:256(title) +#: C/empathy.xml:255(title) msgid "Empathy Main Components" msgstr "Componentes principales de Empathy" -#: C/empathy.xml:263(para) +#: C/empathy.xml:262(para) msgid "Component" msgstr "Componente" -#: C/empathy.xml:266(para) +#: C/empathy.xml:265(para) msgid "Description" msgstr "Descripción" -#: C/empathy.xml:273(para) +#: C/empathy.xml:272(para) msgid "Menubar" msgstr "Barra de menú" -#: C/empathy.xml:276(para) +#: C/empathy.xml:275(para) msgid "" "Contains menus used to perform actions in Empathy." msgstr "" "Contiene los menús usados para realizar acciones en Empathy." -#: C/empathy.xml:283(para) +#: C/empathy.xml:282(para) msgid "Status Drop-Down List" msgstr "Lista desplegable de estados" -#: C/empathy.xml:286(para) +#: C/empathy.xml:285(para) msgid "Allows to update the status." msgstr "Permite actualizar el estado." -#: C/empathy.xml:293(para) +#: C/empathy.xml:292(para) msgid "Account Button" msgstr "Botón Cuentas" -#: C/empathy.xml:296(para) +#: C/empathy.xml:295(para) msgid "Opens the Accounts dialog." msgstr "Abre el diálogo Cuentas." -#: C/empathy.xml:303(para) +#: C/empathy.xml:302(para) msgid "Contact List" msgstr "Lista de contactos" -#: C/empathy.xml:306(para) +#: C/empathy.xml:305(para) msgid "Shows all the available contacts and their associated status." msgstr "Muestra todos los contactos disponibles y su estado asociado." -#: C/empathy.xml:252(para) +#: C/empathy.xml:251(para) msgid "" " describes the components of " "Empathy's main window. " -#: C/empathy.xml:320(title) +#: C/empathy.xml:319(title) msgid "Accounts" msgstr "Cuentas" -#: C/empathy.xml:321(para) +#: C/empathy.xml:320(para) msgid "" "To use Empathy you need at least one account of " "the supported services." @@ -422,7 +427,7 @@ msgstr "" "Para usar Empathy debe tener al menos una cuenta " "de los servicios soportados." -#: C/empathy.xml:324(para) +#: C/empathy.xml:323(para) msgid "" "If you don't already have an account and you don't have your user " "name and password, you need to register a " @@ -432,7 +437,7 @@ msgstr "" "contraseña, debe registrar una cuenta nueva (consulte " ")." -#: C/empathy.xml:329(para) +#: C/empathy.xml:328(para) msgid "" "In order to talk with other users, also called contacts, you need to use the same service they are using. If, for example, " @@ -444,7 +449,7 @@ msgstr "" "de sus contactos está usando el servicio Jabber, necesita tener una cuenta registrada en ese servicio." -#: C/empathy.xml:336(para) +#: C/empathy.xml:335(para) msgid "" "Empathy can handle as many accounts on any " "supported services as you want and you can have them all open at the same " @@ -454,11 +459,11 @@ msgstr "" "cualquiera de los servicios soportados que quiera añadir y puede tener todas " "ellas abiertas al mismo tiempo." -#: C/empathy.xml:342(title) +#: C/empathy.xml:341(title) msgid "Registering an Account" msgstr "Registrar una cuenta" -#: C/empathy.xml:343(para) +#: C/empathy.xml:342(para) msgid "" "You can freely register an account on any of the following services. Follow " "the instructions reported on each website on how to register your new " @@ -476,7 +481,7 @@ msgstr "" #. Translators: try to find a localized version of the #. registration service website -#: C/empathy.xml:361(para) +#: C/empathy.xml:360(para) msgid "" "The AIM " "service." @@ -486,7 +491,7 @@ msgstr "" #. Translators: try to find a localized version of the #. registration service website -#: C/empathy.xml:368(para) +#: C/empathy.xml:367(para) msgid "" "The Google Talk service." @@ -496,7 +501,7 @@ msgstr "" #. Translators: try to find a localized version of the #. registration service website -#: C/empathy.xml:376(para) +#: C/empathy.xml:375(para) msgid "" "The ICQ " "service." @@ -506,7 +511,7 @@ msgstr "" #. Translators: try to find a localized version of the #. registration service website -#: C/empathy.xml:383(para) +#: C/empathy.xml:382(para) msgid "" "The MSN service." @@ -516,7 +521,7 @@ msgstr "" #. Translators: try to find a localized version of the #. registration service website -#: C/empathy.xml:390(para) +#: C/empathy.xml:389(para) msgid "" "The Yahoo service." @@ -524,12 +529,12 @@ msgstr "" "El servicio Yahoo." -#: C/empathy.xml:352(para) +#: C/empathy.xml:351(para) msgid "Click on the name of the service to visit its website: " msgstr "" "Pulse en el nombre del servicio para visitar su página web: " -#: C/empathy.xml:396(para) +#: C/empathy.xml:395(para) msgid "" "For registering a SIP account, you can use one of the " "following service:" @@ -539,7 +544,7 @@ msgstr "" #. Translators: try to find a localized version of the #. registration service website -#: C/empathy.xml:405(para) +#: C/empathy.xml:404(para) msgid "" "The Ekiga service." @@ -549,7 +554,7 @@ msgstr "" #. Translators: try to find a localized version of the #. registration service website -#: C/empathy.xml:412(para) +#: C/empathy.xml:411(para) msgid "" "The FWD (Free World Dialup) service." @@ -559,7 +564,7 @@ msgstr "" #. Translators: try to find a localized version of the #. registration service website -#: C/empathy.xml:420(para) +#: C/empathy.xml:419(para) msgid "" "The Sipphone service." @@ -567,7 +572,7 @@ msgstr "" "El servicio Sipphone." -#: C/empathy.xml:426(para) +#: C/empathy.xml:425(para) msgid "" "For registering a Jabber account, you " "can use the automatic account creation of EmpathyEmpathy es jabber.org." -#: C/empathy.xml:434(para) +#: C/empathy.xml:433(para) msgid "" "If you already have a Jabber account, " "you can use one of the following services:" @@ -591,12 +596,12 @@ msgstr "" "Si ya tiene una cuenta Jabber puede " "usar uno de los siguientes servicios:" -#: C/empathy.xml:451(title) +#: C/empathy.xml:450(title) msgid "Adding your Account to Empathy" msgstr "Añadir su cuenta a Empathy" -#: C/empathy.xml:456(para) C/empathy.xml:534(para) C/empathy.xml:586(para) -#: C/empathy.xml:619(para) C/empathy.xml:649(para) C/empathy.xml:672(para) +#: C/empathy.xml:455(para) C/empathy.xml:533(para) C/empathy.xml:585(para) +#: C/empathy.xml:618(para) C/empathy.xml:648(para) C/empathy.xml:671(para) msgid "" "From the main window " "(Contact List) click on the account button or press " @@ -606,7 +611,7 @@ msgstr "" "(Lista de contactos) pulse en el botón de cuentas o " "F4 para abrir el diálogo Cuentas." -#: C/empathy.xml:468(para) C/empathy.xml:485(para) +#: C/empathy.xml:467(para) C/empathy.xml:484(para) msgid "" "From the Type drop-down list choose the service you " "wish to add an account for, then click on the Create " @@ -616,7 +621,7 @@ msgstr "" "el que quiere crear la cuenta, después pulse en el botón Crear." -#: C/empathy.xml:464(para) +#: C/empathy.xml:463(para) msgid "" "If it is the first time you launch Empathy: " "" @@ -624,15 +629,15 @@ msgstr "" "Si ésta es la primera vez que lanza Empathy: " "" -#: C/empathy.xml:480(para) +#: C/empathy.xml:479(para) msgid "Click on the Add button." msgstr "Pulse el botón Añadir." -#: C/empathy.xml:476(para) +#: C/empathy.xml:475(para) msgid "Otherwise: " msgstr "De otra forma: " -#: C/empathy.xml:495(para) +#: C/empathy.xml:494(para) msgid "" "Fill the required fields with your user name and " "password. Optionally, you can modify some advanced " @@ -644,7 +649,7 @@ msgstr "" "opciones avanzadas. Para obtener más información consulte ." -#: C/empathy.xml:504(para) C/empathy.xml:567(para) +#: C/empathy.xml:503(para) C/empathy.xml:566(para) msgid "" "To enable the new account, select the Enabled check-box " "next to the name of the account in the box on the left." @@ -653,7 +658,7 @@ msgstr "" "Activada junto al nombre de la cuenta, en la caja de la " "izquierda." -#: C/empathy.xml:452(para) +#: C/empathy.xml:451(para) msgid "" "To add your account to Empathy, proceed as " "follows: " @@ -661,11 +666,11 @@ msgstr "" "Para añadir su cuenta a Empathy, proceda como " "sigue: " -#: C/empathy.xml:514(title) +#: C/empathy.xml:513(title) msgid "Importing Accounts" msgstr "Importar cuentas" -#: C/empathy.xml:515(para) +#: C/empathy.xml:514(para) msgid "" "If you use another instant messaging program, you can import the accounts " "from that program into Empathy" @@ -673,7 +678,7 @@ msgstr "" "Si usa otro programa de mensajería instantánea puede importar las cuentas de " "ese programa en Empathy" -#: C/empathy.xml:521(para) +#: C/empathy.xml:520(para) msgid "" "At the moment Empathy can import the accounts " "only from the instant messaging program Pidgin. " @@ -685,7 +690,7 @@ msgstr "" "información acerca de Pidgin consulte la página web de Pidgin." -#: C/empathy.xml:542(para) +#: C/empathy.xml:541(para) msgid "" "Click on the Import Accounts... button to open the " "Import Accounts dialog." @@ -693,7 +698,7 @@ msgstr "" "Pulse en el botón Importar cuentas... para abrir el " "diálogo Importar cuentas." -#: C/empathy.xml:549(para) +#: C/empathy.xml:548(para) msgid "" "Select the accounts you would like to import by clicking on the " "Import check-box." @@ -701,7 +706,7 @@ msgstr "" "Seleccione la cuenta que quiere importar pulsando en la casilla de selección " "Importar." -#: C/empathy.xml:555(para) +#: C/empathy.xml:554(para) msgid "" "When you have selected all the desired accounts, click OK to import them. If you don't want to import the accounts, click " @@ -711,7 +716,7 @@ msgstr "" "Aceptar para importarlas. Si no quiere importar las " "cuentas, pulse el botón Cancelar." -#: C/empathy.xml:563(para) +#: C/empathy.xml:562(para) msgid "" "When you import a new account into Empathy, it " "will not be enabled by default." @@ -719,7 +724,7 @@ msgstr "" "Al importar una cuenta nueva en Empathy no se " "activará de forma predeterminada." -#: C/empathy.xml:530(para) +#: C/empathy.xml:529(para) msgid "" "To import the accounts into Empathy, proceed as " "follows: " @@ -727,19 +732,19 @@ msgstr "" "Para importar cuentas en Empathy proceda como " "sigue: " -#: C/empathy.xml:579(title) +#: C/empathy.xml:578(title) msgid "Editing an Account" msgstr "Editar una cuenta" -#: C/empathy.xml:594(para) +#: C/empathy.xml:593(para) msgid "Select the account you wish to edit in the box on the left." msgstr "Seleccione la cuenta que quiere editar en la caja a la izquierda." -#: C/empathy.xml:600(para) +#: C/empathy.xml:599(para) msgid "Modify the desired data." msgstr "Modifique los datos deseados." -#: C/empathy.xml:580(para) +#: C/empathy.xml:579(para) msgid "" "To edit one of your accounts, i.e. to change the password or your user name, proceed as follows: " @@ -749,12 +754,12 @@ msgstr "" "contraseña o su usuario, proceda " "como sigue: " -#: C/empathy.xml:608(para) +#: C/empathy.xml:607(para) msgid "" "Based on the type of the account, it is possibile to edit different settings." msgstr "Basado en el tipo de cuenta, es posible editar diferentes ajustes." -#: C/empathy.xml:627(para) +#: C/empathy.xml:626(para) msgid "" "Select the account you wish to edit in the box on the left and double-click " "on its name." @@ -762,11 +767,11 @@ msgstr "" "Seleccione la cuenta que quiere editar en la caja de la izquierda y pulse " "dos veces en su nombre." -#: C/empathy.xml:633(para) +#: C/empathy.xml:632(para) msgid "Change the name of the account as you desire." msgstr "Cambie el nombre de la cuenta como desee." -#: C/empathy.xml:614(para) +#: C/empathy.xml:613(para) msgid "" "To modify the identifier of an account, how Empathy identifies an account, proceed as follows: " @@ -775,15 +780,15 @@ msgstr "" "Empathy identifica a la cuente, proceda como " "sigue: " -#: C/empathy.xml:642(title) +#: C/empathy.xml:641(title) msgid "Disabling and Removing an Account" msgstr "Desactivar y quitaruna cuenta" -#: C/empathy.xml:643(para) +#: C/empathy.xml:642(para) msgid "To disable an account, proceed as follows:" msgstr "Para desactivar una cuenta, proceda como sigue:" -#: C/empathy.xml:658(para) +#: C/empathy.xml:657(para) msgid "" "Select the account you wish to disable in the box on the left of the dialog " "and deselect the Enabled check-box." @@ -792,22 +797,22 @@ msgstr "" "diálogo y deselecicone la casilla de verificación Activada." -#: C/empathy.xml:666(para) +#: C/empathy.xml:665(para) msgid "To remove an account, proceed as follows:" msgstr "Para quitar una cuenta, proceda como sigue:" -#: C/empathy.xml:681(para) +#: C/empathy.xml:680(para) msgid "" "Select the account you wish to disable in the box on the left of the dialog." msgstr "" "Seleccione la cuenta que desea desactivar en la caja a la izquierda del " "diálogo." -#: C/empathy.xml:687(para) +#: C/empathy.xml:686(para) msgid "Click on the Remove button." msgstr "Pulse en el botón Quitar." -#: C/empathy.xml:692(para) +#: C/empathy.xml:691(para) msgid "" "A dialog will be shown asking for confirmation. Click on the " "Remove button to remove the account." @@ -815,11 +820,11 @@ msgstr "" "Se mostrará un diálogo preguntando por una confirmación. Pulse en el botón " "Quitar para quitar la cuenta." -#: C/empathy.xml:702(title) +#: C/empathy.xml:701(title) msgid "Editing Personal Information" msgstr "Editar información personal" -#: C/empathy.xml:703(para) +#: C/empathy.xml:702(para) msgid "" "To change your personal information, your alias and your icon (the image " "that other contacts will see of you), for each of your accounts, proceed as " @@ -829,7 +834,7 @@ msgstr "" "que otros contactos le ven), para cada una de las cuentas, proceda como " "sigue:" -#: C/empathy.xml:711(para) +#: C/empathy.xml:710(para) msgid "" "From the main window, select " "EditPersonal InformationEditarInformación " "personal." -#: C/empathy.xml:720(para) +#: C/empathy.xml:719(para) msgid "" "From the Account drop-down list, choose the account you " "want to edit." @@ -847,11 +852,11 @@ msgstr "" "Desde la lista desplegable Cuenta, elija la cuenta que " "quiere editar." -#: C/empathy.xml:726(para) +#: C/empathy.xml:725(para) msgid "In the Alias text box, write your new alias." msgstr "En la caja de texto Apodo escriba su nuevo apodo." -#: C/empathy.xml:732(para) +#: C/empathy.xml:731(para) msgid "" "To change your icon, click on the person-looking button and choose an image " "file." @@ -859,11 +864,11 @@ msgstr "" "Para cambiar su icono pulse en el botón de apariencia personal y elija un " "archivo de imagen." -#: C/empathy.xml:738(para) C/empathy.xml:1319(para) C/empathy.xml:1353(para) +#: C/empathy.xml:737(para) C/empathy.xml:1318(para) C/empathy.xml:1352(para) msgid "When done, click Close." msgstr "Cuando termine pulse Cerrar." -#: C/empathy.xml:746(para) +#: C/empathy.xml:745(para) msgid "" "An alias is an alternative way you can identify " "yourself. You can use your real name or a nickname." @@ -871,11 +876,11 @@ msgstr "" "Un apodo es una forma alternativa por la que se puede " "identificar. Puede usar su nombre real o un apodo." -#: C/empathy.xml:756(title) +#: C/empathy.xml:755(title) msgid "Advanced Options" msgstr "Opciones avanzadas" -#: C/empathy.xml:757(para) +#: C/empathy.xml:756(para) msgid "" "Based on the service you are using, it is possible to configure more " "advanced options to modify the normal behavior of EmpathyEmpathy." -#: C/empathy.xml:762(para) +#: C/empathy.xml:761(para) msgid "" "To configure these options, when you are adding a new account, click on the drop-down section " @@ -895,15 +900,15 @@ msgstr "" "account\">añadiendo una cuenta nueva, pulse la sección desplegable " "Avanzadas." -#: C/empathy.xml:770(title) +#: C/empathy.xml:769(title) msgid "Jabber (or XMPP) and Google Talk" msgstr "Jabber (o XMPP) y Google Talk" -#: C/empathy.xml:777(guilabel) +#: C/empathy.xml:776(guilabel) msgid "Encryption required (TLS/SSL)" msgstr "Se requiere cifrado (TLS/SSL)" -#: C/empathy.xml:780(para) +#: C/empathy.xml:779(para) msgid "" "Select this option in order to use some sort of encryption during your " "conversations." @@ -911,11 +916,11 @@ msgstr "" "Seleccione esta opción para usar algún tipo de cifrado durante sus " "conversaciones." -#: C/empathy.xml:788(guilabel) +#: C/empathy.xml:787(guilabel) msgid "Ignore SSL certificate errors" msgstr "Ignorar los errores de certificados SSL" -#: C/empathy.xml:791(para) +#: C/empathy.xml:790(para) msgid "" "Select this option in order to ignore the errors that can be generated by " "some types of security certificates. Usually these certificates are called " @@ -925,7 +930,7 @@ msgstr "" "tipos de certificados de seguridad. Generalmente esos certificados se llaman " "autofirmados." -#: C/empathy.xml:799(para) +#: C/empathy.xml:798(para) msgid "" "Select this option only if you are sure the certificate is secure and you " "can trust it." @@ -933,20 +938,11 @@ msgstr "" "Seleccione esta opción sólo si está seguro de que su certificado es seguro y " "puede confiar en él." -#: C/empathy.xml:809(guilabel) +#: C/empathy.xml:808(guilabel) msgid "Resource" msgstr "Recurso" -#: C/empathy.xml:812(para) -#| msgid "" -#| "Use this text box to set a name with which you can identify the running " -#| "program based on where you are running it. With this option, and the " -#| "Priority one, you can use your account " -#| "simultaneously in two different devices. For example, if you set one " -#| "device to desktop and of the other one to " -#| "mobile, you can connect with both of them and " -#| "based on the Priority value you will receive " -#| "messages on one of the two devices or both." +#: C/empathy.xml:811(para) msgid "" "Use this text box to set a name with which you can identify the running " "program based on where you are running it. With this option, and the " @@ -966,7 +962,7 @@ msgstr "" "dispositivos y basándose en el valor Prioridad recibirá " "los mensajes en uno de los dispositivos o en ambos." -#: C/empathy.xml:825(para) +#: C/empathy.xml:824(para) msgid "" "This can be useful if you have two devices, a main one and a portable one, " "and you move away from the main one bringing with you the other: you can " @@ -978,7 +974,7 @@ msgstr "" "mensajes desde su cuenta con el dispositivo portable incluso si no " "desconecta el principal." -#: C/empathy.xml:834(para) +#: C/empathy.xml:833(para) msgid "" "If you set the same value for this text box on both the devices, when you " "connect with one of them, the other one will be disconnected, even if you " @@ -989,11 +985,11 @@ msgstr "" "establece un valor diferente en la caja incrementable Prioridad." -#: C/empathy.xml:847(guilabel) +#: C/empathy.xml:846(guilabel) msgid "Priority" msgstr "Prioridad" -#: C/empathy.xml:850(para) +#: C/empathy.xml:849(para) msgid "" "Use this spin box to indicate wich device, set in the Resource text box, will receive the new messages. The higher the number, " @@ -1005,7 +1001,7 @@ msgstr "" "Cuanto mayor sea el número, mayor será la prioridad: recibirá los mensajes " "nuevos en el dispositivo con el número más alto." -#: C/empathy.xml:857(para) +#: C/empathy.xml:856(para) msgid "" "You can set values in the range from -128 to " "127." @@ -1013,7 +1009,7 @@ msgstr "" "Puede establecer valores en el rango de -128 a " "127." -#: C/empathy.xml:863(para) +#: C/empathy.xml:862(para) msgid "" "If you set the same value of this spin box in both the devices, you will " "receive messages on both of them." @@ -1021,13 +1017,13 @@ msgstr "" "Si establece el mismo valor de esta caja incrementable en ambos " "dispositivos, recibirá mensajes en ambos dos." -#: C/empathy.xml:880(guilabel) C/empathy.xml:973(guilabel) -#: C/empathy.xml:1021(guilabel) C/empathy.xml:1115(guilabel) +#: C/empathy.xml:879(guilabel) C/empathy.xml:972(guilabel) +#: C/empathy.xml:1020(guilabel) C/empathy.xml:1114(guilabel) msgid "Server" msgstr "Servidor" -#: C/empathy.xml:883(para) C/empathy.xml:976(para) C/empathy.xml:1024(para) -#: C/empathy.xml:1118(para) +#: C/empathy.xml:882(para) C/empathy.xml:975(para) C/empathy.xml:1023(para) +#: C/empathy.xml:1117(para) msgid "" "Use this text box to write the name of the server you want to use for this " "service." @@ -1035,20 +1031,20 @@ msgstr "" "Use esta caja de texto para escribir el nombre del servidor que quiere usar " "para este servicio." -#: C/empathy.xml:891(guilabel) C/empathy.xml:984(guilabel) -#: C/empathy.xml:1032(guilabel) C/empathy.xml:1126(guilabel) +#: C/empathy.xml:890(guilabel) C/empathy.xml:983(guilabel) +#: C/empathy.xml:1031(guilabel) C/empathy.xml:1125(guilabel) msgid "Port" msgstr "Puerto" -#: C/empathy.xml:894(para) C/empathy.xml:987(para) C/empathy.xml:1035(para) -#: C/empathy.xml:1129(para) +#: C/empathy.xml:893(para) C/empathy.xml:986(para) C/empathy.xml:1034(para) +#: C/empathy.xml:1128(para) msgid "Use this spin box to set the number of the port of the server to use." msgstr "" "Use esta caja incrementable para establecer el número del puerto del " "servidor que usar." -#: C/empathy.xml:898(para) C/empathy.xml:991(para) C/empathy.xml:1039(para) -#: C/empathy.xml:1133(para) +#: C/empathy.xml:897(para) C/empathy.xml:990(para) C/empathy.xml:1038(para) +#: C/empathy.xml:1132(para) msgid "" "You can set values in the range from 0 to " "65,555." @@ -1056,11 +1052,11 @@ msgstr "" "Puede establecer valores en el rango de 0 a " "65.555." -#: C/empathy.xml:906(guilabel) +#: C/empathy.xml:905(guilabel) msgid "Use old SSL" msgstr "Usar SSL antiguo" -#: C/empathy.xml:909(para) +#: C/empathy.xml:908(para) msgid "" "Select this option to use the old version of the secure protocol for " "encrypting your connection." @@ -1068,7 +1064,7 @@ msgstr "" "Seleccione esta opción para usar la versión antigua del protocolo seguro " "para cifrar su conexión." -#: C/empathy.xml:874(para) +#: C/empathy.xml:873(para) msgid "" "In the Override server settings section you can set " "options that take precedence over the default settings. " @@ -1077,22 +1073,22 @@ msgstr "" "puede establecer opciones que tienen preferencia sobre los ajustes " "predeterminados. " -#: C/empathy.xml:925(guilabel) +#: C/empathy.xml:924(guilabel) msgid "Ignore conference and chatrooms invitations" msgstr "Ignorar invitaciones a conferencias y salas de chat" -#: C/empathy.xml:929(para) +#: C/empathy.xml:928(para) msgid "" "Select this option to ignore the invitations that other people may send you." msgstr "" "Seleccione esta opción para ignorar las invitaciones que otras personas " "pueden enviarle." -#: C/empathy.xml:937(guilabel) +#: C/empathy.xml:936(guilabel) msgid "Room List locale" msgstr "Configuración de la lista de salas" -#: C/empathy.xml:940(para) +#: C/empathy.xml:939(para) msgid "" "The value of this text box identifies the language used to retrieve the room " "list when connecting to the Yahoo service." @@ -1100,17 +1096,17 @@ msgstr "" "El valor de esta caja de texto identifica el idioma que usar al obtener la " "lista de salas al conectar con el servicio de Yahoo!" -#: C/empathy.xml:945(para) +#: C/empathy.xml:944(para) msgid "" "If you need to change this value, use the two letter code of your language." msgstr "" "Si necesita cambiar ese valor use el código de dos letras para su idioma." -#: C/empathy.xml:953(guilabel) C/empathy.xml:1095(guilabel) +#: C/empathy.xml:952(guilabel) C/empathy.xml:1094(guilabel) msgid "Charset" msgstr "Conjunto de caracteres" -#: C/empathy.xml:956(para) C/empathy.xml:1098(para) +#: C/empathy.xml:955(para) C/empathy.xml:1097(para) msgid "" "The value of this text box identifies the set of the characters used by " "Empathy." @@ -1118,7 +1114,7 @@ msgstr "" "El valor de esta caja de texto identifica el conjunto de caracteres que usa " "Empathy." -#: C/empathy.xml:962(para) C/empathy.xml:1104(para) +#: C/empathy.xml:961(para) C/empathy.xml:1103(para) msgid "" "It is advise to leave this value to UTF-8. Change it only " "if that charset does not cover your language." @@ -1126,11 +1122,11 @@ msgstr "" "Se recomienda dejar este valor en UTF-8. Cámbielo sólo si " "ese conjunto de caracteres no cubre su idioma." -#: C/empathy.xml:999(guilabel) +#: C/empathy.xml:998(guilabel) msgid "Use Yahoo Japan" msgstr "Usar Yahoo Japón" -#: C/empathy.xml:1002(para) +#: C/empathy.xml:1001(para) msgid "" "Select this option only if you have a Yahoo! Japan account. With the Yahoo! " "Japan service you can only use a Yahoo! Japan account: if you have " @@ -1142,15 +1138,15 @@ msgstr "" "registrado una cuenta con la versión inglesa del servicio, esa cuenta no " "funcionará." -#: C/empathy.xml:1016(title) +#: C/empathy.xml:1015(title) msgid "AIM, GroupWise and MSN" msgstr "AIM, GroupWise y MSN" -#: C/empathy.xml:1055(guilabel) +#: C/empathy.xml:1054(guilabel) msgid "Published Name" msgstr "Nombre publicado" -#: C/empathy.xml:1058(para) +#: C/empathy.xml:1057(para) msgid "" "Use this text box to write the name that will be visible to the other users " "of the network." @@ -1158,42 +1154,42 @@ msgstr "" "Use esta caja de texto para escribir el nombre que será visible al resto de " "usuarios de la red." -#: C/empathy.xml:1066(guilabel) +#: C/empathy.xml:1065(guilabel) msgid "Email" msgstr "Correo-e" -#: C/empathy.xml:1069(para) +#: C/empathy.xml:1068(para) msgid "Use this text box to write your email." msgstr "Use esta caja de texto para escribir su correo-e." -#: C/empathy.xml:1076(guilabel) +#: C/empathy.xml:1075(guilabel) msgid "Jabber ID" msgstr "ID Jabber" -#: C/empathy.xml:1079(para) +#: C/empathy.xml:1078(para) msgid "Use this text box to write your Jabber ID, if you have one." msgstr "Use esta caja de texto para escribir su ID Jabber, si tiene uno." -#: C/empathy.xml:1144(title) +#: C/empathy.xml:1143(title) msgid "Gadu Gadu" msgstr "Gadu Gadu" -#: C/empathy.xml:1148(guilabel) +#: C/empathy.xml:1147(guilabel) msgid "Nick" msgstr "Apodo" -#: C/empathy.xml:1150(para) +#: C/empathy.xml:1149(para) msgid "" "Use this text box to write an alternative name to use with this service." msgstr "" "Use esta caja de texto para escribir un nombre alternativo que usar con este " "servicio." -#: C/empathy.xml:1165(title) +#: C/empathy.xml:1164(title) msgid "Contacts and Groups" msgstr "Contactos y grupos" -#: C/empathy.xml:1166(para) +#: C/empathy.xml:1165(para) msgid "" "All the contacts are handled within Empathy's " "main window." @@ -1201,7 +1197,7 @@ msgstr "" "Todos los contactos se gestionan en la ventana principal de Empathy." -#: C/empathy.xml:1170(para) +#: C/empathy.xml:1169(para) msgid "" "You can add or remove a contact or you can edit the information of a " "particular contact. It is also possibile to arrange contacts in groups. You " @@ -1213,15 +1209,15 @@ msgstr "" "Puede tener un grupo para sus contactos del trabajo, uno para los contactos " "de su familia, y demás." -#: C/empathy.xml:1177(title) +#: C/empathy.xml:1176(title) msgid "Adding and Removing a Contact" msgstr "Añadir y quitar un contacto" -#: C/empathy.xml:1178(para) +#: C/empathy.xml:1177(para) msgid "To add a new contact, proceed as follows:" msgstr "Para añadir un contacto nuevo, proceda como sigue:" -#: C/empathy.xml:1184(para) +#: C/empathy.xml:1183(para) msgid "" "From the main window choose " "ChatAdd Contact.... Se mostrará el diálogo Contacto nuevo." -#: C/empathy.xml:1194(para) +#: C/empathy.xml:1193(para) msgid "" "From the Account drop-down list, choose the service " "used by the contact you are adding." @@ -1241,7 +1237,7 @@ msgstr "" "Desde la lista desplegable Cuenta, elija el servicio " "que usa el contacto que está añadiendo." -#: C/empathy.xml:1200(para) +#: C/empathy.xml:1199(para) msgid "" "In the Identifier text box type the address of the contact in the form of user name@servicio\n" "\t dominio." -#: C/empathy.xml:1209(para) +#: C/empathy.xml:1208(para) msgid "" "In the Alias text box type the name you want to give at " "the the new contact." @@ -1262,15 +1258,15 @@ msgstr "" "En la caja de texto Apodo escriba el nombre que quiere " "darle a su nuevo contacto." -#: C/empathy.xml:1215(para) +#: C/empathy.xml:1214(para) msgid "Click on Add to add the new contact." msgstr "Pulse en Añadir para añadir el contacto nuevo." -#: C/empathy.xml:1221(para) +#: C/empathy.xml:1220(para) msgid "To remove a contact, proceed as follows:" msgstr "Para quitar un contacto, proceda como sigue:" -#: C/empathy.xml:1227(para) +#: C/empathy.xml:1226(para) msgid "" "From the main window, select " "the contact you would like to remove and right-click on it." @@ -1279,7 +1275,7 @@ msgstr "" "seleccione el contacto que quiere quitar y pulse con el botón derecho sobre " "él." -#: C/empathy.xml:1234(para) +#: C/empathy.xml:1233(para) msgid "" "From the popup menu, choose Remove to remove the " "contact." @@ -1287,7 +1283,7 @@ msgstr "" "Desde el menú emergente, elija Quitar para quitar el " "contacto." -#: C/empathy.xml:1243(para) C/empathy.xml:1279(para) +#: C/empathy.xml:1242(para) C/empathy.xml:1278(para) msgid "" "An alias is an alternative way you can identify that " "particular contact. You can use the real name or the nickname of that person." @@ -1295,21 +1291,15 @@ msgstr "" "Un apodo es una forma alternativa de identificar un " "contacto en particular. Puede usar el nombre real o el apodo de esa persona." -#: C/empathy.xml:1252(title) +#: C/empathy.xml:1251(title) msgid "Editing a Contact" msgstr "Editar un contacto" -#: C/empathy.xml:1253(para) +#: C/empathy.xml:1252(para) msgid "To edit a contact, proceed as follows:" msgstr "Para editar un contacto, proceda como sigue:" -#: C/empathy.xml:1259(para) C/empathy.xml:1301(para) -#| msgid "" -#| "From the main window, " -#| "select the contact you would like to modify and choose " -#| "EditAccountModify, or right-click " -#| "on it and choose Modify." +#: C/empathy.xml:1258(para) C/empathy.xml:1300(para) msgid "" "From the main window, select " "the contact you would like to modify and choose EditEditar o pulse con el " "botón derecho sobre él y elija Editar." -#: C/empathy.xml:1272(para) +#: C/empathy.xml:1271(para) msgid "" "From the Edit Contact Information dialog, you can " "modify the alias and the group of " @@ -1332,7 +1322,7 @@ msgstr "" "modificar el apodp y el grupo del " "contacto." -#: C/empathy.xml:1286(para) +#: C/empathy.xml:1285(para) msgid "" "For more information about groups, see and ." @@ -1340,15 +1330,15 @@ msgstr "" "Para obtener más información acerca de los grupos, consulte y ." -#: C/empathy.xml:1294(title) +#: C/empathy.xml:1293(title) msgid "Adding a Contact to a Group" msgstr "Añadir un contacto a un grupo" -#: C/empathy.xml:1295(para) +#: C/empathy.xml:1294(para) msgid "To add a contact to one or more groups, proceed as follows:" msgstr "Para añadir un contacto a uno o más grupos, proceda como sigue:" -#: C/empathy.xml:1313(para) +#: C/empathy.xml:1312(para) msgid "" "From the Groups section, select the group, or groups, " "you want to add the contact to." @@ -1356,21 +1346,15 @@ msgstr "" "En la sección Grupos, seleccione el grupo o grupos a " "los que quiera añadir el contacto." -#: C/empathy.xml:1328(title) +#: C/empathy.xml:1327(title) msgid "Adding a New Group" msgstr "Añadir un grupo nuevo" -#: C/empathy.xml:1329(para) +#: C/empathy.xml:1328(para) msgid "To add a new group, proceed as follows:" msgstr "Para añadir un grupo nuevo, proceda como sigue:" -#: C/empathy.xml:1335(para) -#| msgid "" -#| "From the main window, " -#| "select one contact and choose EditAccountModify, or right-click on it and choose " -#| "Modify." +#: C/empathy.xml:1334(para) msgid "" "From the main window, select " "one contact and choose EditContactoEditar o pulse con el botón derecho y elija Editar." -#: C/empathy.xml:1346(para) +#: C/empathy.xml:1345(para) msgid "" "In the Groups section, write the name of the group you " "want to add and then click on Add Group." diff --git a/libempathy-gtk/Makefile.am b/libempathy-gtk/Makefile.am index 6f3b99ba..2065589e 100644 --- a/libempathy-gtk/Makefile.am +++ b/libempathy-gtk/Makefile.am @@ -49,7 +49,7 @@ libempathy_gtk_la_SOURCES = \ empathy-profile-chooser.c \ empathy-smiley-manager.c \ empathy-spell.c \ - empathy-spell-dialog.c \ + empathy-status-preset-dialog.c \ empathy-theme-boxes.c \ empathy-theme-irc.c \ empathy-theme-manager.c \ @@ -102,7 +102,7 @@ libempathy_gtk_headers = \ empathy-profile-chooser.h \ empathy-smiley-manager.h \ empathy-spell.h \ - empathy-spell-dialog.h \ + empathy-status-preset-dialog.h \ empathy-theme-boxes.h \ empathy-theme-irc.h \ empathy-theme-manager.h \ @@ -117,7 +117,6 @@ uidir = $(datadir)/empathy ui_DATA = \ empathy-contact-widget.ui \ empathy-contact-dialogs.ui \ - empathy-presence-chooser.ui \ empathy-account-widget-generic.ui \ empathy-account-widget-jabber.ui \ empathy-account-widget-msn.ui \ @@ -128,7 +127,7 @@ ui_DATA = \ empathy-account-widget-yahoo.ui \ empathy-account-widget-groupwise.ui \ empathy-account-widget-aim.ui \ - empathy-spell-dialog.ui \ + empathy-status-preset-dialog.ui \ empathy-log-window.ui \ empathy-chat.ui \ empathy-new-message-dialog.ui diff --git a/libempathy-gtk/empathy-account-chooser.c b/libempathy-gtk/empathy-account-chooser.c index 8c402c07..5d11e8e1 100644 --- a/libempathy-gtk/empathy-account-chooser.c +++ b/libempathy-gtk/empathy-account-chooser.c @@ -37,6 +37,23 @@ #include "empathy-ui-utils.h" #include "empathy-account-chooser.h" +/** + * SECTION:empathy-account-chooser + * @title:EmpathyAccountChooser + * @short_description: A widget used to choose from a list of accounts + * @include: libempathy-gtk/empathy-account-chooser.h + * + * #EmpathyAccountChooser is a widget which extends #GtkComboBox to provide + * a chooser of available accounts. + */ + +/** + * EmpathyAccountChooser: + * @parent: parent object + * + * Widget which extends #GtkComboBox to provide a chooser of available accounts. + */ + #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccountChooser) typedef struct { EmpathyAccountManager *manager; @@ -112,6 +129,11 @@ empathy_account_chooser_class_init (EmpathyAccountChooserClass *klass) object_class->get_property = account_chooser_get_property; object_class->set_property = account_chooser_set_property; + /** + * EmpathyAccountChooser:has-all-option: + * + * Have an additional option in the list to mean all accounts. + */ g_object_class_install_property (object_class, PROP_HAS_ALL_OPTION, g_param_spec_boolean ("has-all-option", @@ -209,6 +231,13 @@ account_chooser_set_property (GObject *object, }; } +/** + * empathy_account_chooser_new: + * + * Creates a new #EmpathyAccountChooser. + * + * Return value: A new #EmpathyAccountChooser + */ GtkWidget * empathy_account_chooser_new (void) { @@ -219,8 +248,18 @@ empathy_account_chooser_new (void) return chooser; } +/** + * empathy_account_chooser_dup_account: + * @chooser: an #EmpathyAccountChooser + * + * Returns the account which is currently selected in the chooser or %NULL + * if there is no account selected. The #McAccount returned should be + * unrefed with g_object_unref() when finished with. + * + * Return value: a new ref to the #McAccount currently selected, or %NULL. + */ McAccount * -empathy_account_chooser_get_account (EmpathyAccountChooser *chooser) +empathy_account_chooser_dup_account (EmpathyAccountChooser *chooser) { EmpathyAccountChooserPriv *priv; McAccount *account; @@ -241,6 +280,44 @@ empathy_account_chooser_get_account (EmpathyAccountChooser *chooser) return account; } +/** + * empathy_account_chooser_get_connection: + * @chooser: an #EmpathyAccountChooser + * + * Returns a borrowed reference to the #TpConnection associated with the + * account currently selected. The caller must reference the returned object with + * g_object_ref() if it will be kept + * + * Return value: a borrowed reference to the #TpConnection associated with the + * account curently selected. + */ +TpConnection * +empathy_account_chooser_get_connection (EmpathyAccountChooser *chooser) +{ + EmpathyAccountChooserPriv *priv; + McAccount *account; + TpConnection *connection; + + g_return_val_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser), NULL); + + priv = GET_PRIV (chooser); + + account = empathy_account_chooser_dup_account (chooser); + connection = empathy_account_manager_get_connection (priv->manager, account); + g_object_unref (account); + + return connection; +} + +/** + * empathy_account_chooser_set_account: + * @chooser: an #EmpathyAccountChooser + * @account: an #McAccount + * + * Sets the currently selected account to @account, if it exists in the list. + * + * Return value: whether the chooser was set to @account. + */ gboolean empathy_account_chooser_set_account (EmpathyAccountChooser *chooser, McAccount *account) @@ -266,6 +343,16 @@ empathy_account_chooser_set_account (EmpathyAccountChooser *chooser, return data.set; } +/** + * empathy_account_chooser_get_has_all_option: + * @chooser: an #EmpathyAccountChooser + * + * Returns whether @chooser has the #EmpathyAccountChooser:has-all-option property + * set to true. + * + * Return value: whether @chooser has the #EmpathyAccountChooser:has-all-option property + * enabled. + */ gboolean empathy_account_chooser_get_has_all_option (EmpathyAccountChooser *chooser) { @@ -278,6 +365,13 @@ empathy_account_chooser_get_has_all_option (EmpathyAccountChooser *chooser) return priv->has_all_option; } +/** + * empathy_account_chooser_set_has_all_option: + * @chooser: an #EmpathyAccountChooser + * @has_all_option: a new value for the #EmpathyAccountChooser:has-all-option property + * + * Sets the #EmpathyAccountChooser:has-all-option property. + */ void empathy_account_chooser_set_has_all_option (EmpathyAccountChooser *chooser, gboolean has_all_option) @@ -618,6 +712,15 @@ account_chooser_filter_foreach (GtkTreeModel *model, return FALSE; } +/** + * empathy_account_chooser_set_filter: + * @chooser: an #EmpathyAccountChooser + * @filter: a filter + * @user_data: data to pass to @filter, or %NULL + * + * Sets a filter on the @chooser so only accounts that are %TRUE in the eyes + * of the filter are visible in the @chooser. + */ void empathy_account_chooser_set_filter (EmpathyAccountChooser *chooser, EmpathyAccountChooserFilterFunc filter, @@ -639,6 +742,27 @@ empathy_account_chooser_set_filter (EmpathyAccountChooser *chooser, gtk_tree_model_foreach (model, account_chooser_filter_foreach, chooser); } +/** + * EmpathyAccountChooserFilterFunc: + * @account: an #McAccount + * @user_data: user data, or %NULL + * + * A function which decides whether the account indicated by @account + * is visible. + * + * Return value: whether the account indicated by @account is visible. + */ + +/** + * empathy_account_chooser_filter_is_connected: + * @account: an #McAccount + * @user_data: user data or %NULL + * + * A useful #EmpathyAccountChooserFilterFunc that one could pass into + * empathy_account_chooser_set_filter() and only show connected accounts. + * + * Return value: Whether @account is connected + */ gboolean empathy_account_chooser_filter_is_connected (McAccount *account, gpointer user_data) diff --git a/libempathy-gtk/empathy-account-chooser.h b/libempathy-gtk/empathy-account-chooser.h index c15923bc..98d568bc 100644 --- a/libempathy-gtk/empathy-account-chooser.h +++ b/libempathy-gtk/empathy-account-chooser.h @@ -47,6 +47,8 @@ typedef struct _EmpathyAccountChooserClass EmpathyAccountChooserClass; struct _EmpathyAccountChooser { GtkComboBox parent; + + /**/ gpointer priv; }; @@ -56,7 +58,8 @@ struct _EmpathyAccountChooserClass { GType empathy_account_chooser_get_type (void) G_GNUC_CONST; GtkWidget * empathy_account_chooser_new (void); -McAccount * empathy_account_chooser_get_account (EmpathyAccountChooser *chooser); +McAccount * empathy_account_chooser_dup_account (EmpathyAccountChooser *chooser); +TpConnection * empathy_account_chooser_get_connection (EmpathyAccountChooser *chooser); gboolean empathy_account_chooser_set_account (EmpathyAccountChooser *chooser, McAccount *account); gboolean empathy_account_chooser_get_has_all_option (EmpathyAccountChooser *chooser); diff --git a/libempathy-gtk/empathy-account-widget-irc.c b/libempathy-gtk/empathy-account-widget-irc.c index 3af84241..cc86a5aa 100644 --- a/libempathy-gtk/empathy-account-widget-irc.c +++ b/libempathy-gtk/empathy-account-widget-irc.c @@ -50,9 +50,6 @@ typedef struct { GtkWidget *vbox_settings; GtkWidget *combobox_network; - GtkWidget *button_add_network; - GtkWidget *button_network; - GtkWidget *button_remove; } EmpathyAccountWidgetIrc; enum { @@ -462,9 +459,6 @@ empathy_account_widget_irc_new (McAccount *account) gui = empathy_builder_get_file (filename, "vbox_irc_settings", &settings->vbox_settings, "combobox_network", &settings->combobox_network, - "button_network", &settings->button_network, - "button_add_network", &settings->button_add_network, - "button_remove", &settings->button_remove, NULL); g_free (filename); @@ -501,7 +495,7 @@ empathy_account_widget_irc_new (McAccount *account) "vbox_irc_settings", "destroy", account_widget_irc_destroy_cb, "button_network", "clicked", account_widget_irc_button_edit_network_clicked_cb, "button_add_network", "clicked", account_widget_irc_button_add_network_clicked_cb, - "button_remove", "clicked", account_widget_irc_button_remove_clicked_cb, + "button_remove_network", "clicked", account_widget_irc_button_remove_clicked_cb, "combobox_network", "changed", account_widget_irc_combobox_network_changed_cb, NULL); diff --git a/libempathy-gtk/empathy-account-widget-irc.ui b/libempathy-gtk/empathy-account-widget-irc.ui index f499866e..76c67f71 100644 --- a/libempathy-gtk/empathy-account-widget-irc.ui +++ b/libempathy-gtk/empathy-account-widget-irc.ui @@ -3,7 +3,6 @@ - True 5 Network center-on-parent @@ -418,7 +417,7 @@ - + True True True @@ -444,7 +443,7 @@ - + True 0 Network: diff --git a/libempathy-gtk/empathy-avatar-chooser.c b/libempathy-gtk/empathy-avatar-chooser.c index 02aa689e..c86b85d2 100644 --- a/libempathy-gtk/empathy-avatar-chooser.c +++ b/libempathy-gtk/empathy-avatar-chooser.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include "empathy-avatar-chooser.h" #include "empathy-conf.h" @@ -39,15 +39,31 @@ #define DEBUG_FLAG EMPATHY_DEBUG_OTHER #include +/** + * SECTION:empathy-avatar-chooser + * @title: EmpathyAvatarChooser + * @short_description: A widget used to change avatar + * @include: libempathy-gtk/empathy-avatar-chooser.h + * + * #EmpathyAvatarChooser is a widget which extends #GtkButton to + * provide a way of changing avatar. + */ + +/** + * EmpathyAvatarChooser: + * @parent: parent object + * + * Widget which extends #GtkButton to provide a way of changing avatar. + */ + #define AVATAR_SIZE_SAVE 96 #define AVATAR_SIZE_VIEW 64 #define DEFAULT_DIR DATADIR"/pixmaps/faces" #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAvatarChooser) typedef struct { - EmpathyContactFactory *contact_factory; - McAccount *account; - EmpathyTpContactFactory *tp_contact_factory; + EmpathyTpContactFactory *factory; + TpConnection *connection; GtkFileChooser *chooser_dialog; gulong ready_handler_id; @@ -56,8 +72,8 @@ typedef struct { } EmpathyAvatarChooserPriv; static void avatar_chooser_finalize (GObject *object); -static void avatar_chooser_set_account (EmpathyAvatarChooser *self, - McAccount *account); +static void avatar_chooser_set_connection (EmpathyAvatarChooser *self, + TpConnection *connection); static void avatar_chooser_set_image (EmpathyAvatarChooser *chooser, EmpathyAvatar *avatar, GdkPixbuf *pixbuf, @@ -96,7 +112,7 @@ enum { enum { PROP_0, - PROP_ACCOUNT + PROP_CONNECTION }; static guint signals [LAST_SIGNAL]; @@ -125,8 +141,8 @@ avatar_chooser_get_property (GObject *object, EmpathyAvatarChooserPriv *priv = GET_PRIV (object); switch (param_id) { - case PROP_ACCOUNT: - g_value_set_object (value, priv->account); + case PROP_CONNECTION: + g_value_set_object (value, priv->connection); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -143,8 +159,8 @@ avatar_chooser_set_property (GObject *object, EmpathyAvatarChooser *self = EMPATHY_AVATAR_CHOOSER (object); switch (param_id) { - case PROP_ACCOUNT: - avatar_chooser_set_account (self, g_value_get_object (value)); + case PROP_CONNECTION: + avatar_chooser_set_connection (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -162,6 +178,13 @@ empathy_avatar_chooser_class_init (EmpathyAvatarChooserClass *klass) object_class->get_property = avatar_chooser_get_property; object_class->set_property = avatar_chooser_set_property; + /** + * EmpathyAvatarChooser::changed: + * @chooser: an #EmpathyAvatarChooser + * + * Emitted when the chosen avatar has changed. + * + */ signals[CHANGED] = g_signal_new ("changed", G_TYPE_FROM_CLASS (klass), @@ -171,15 +194,21 @@ empathy_avatar_chooser_class_init (EmpathyAvatarChooserClass *klass) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - param_spec = g_param_spec_object ("account", - "McAccount", - "McAccount whose avatar should be " + /** + * EmpathyAvatarChooser:connection: + * + * The #TpConnection whose avatar should be shown and modified by + * the #EmpathyAvatarChooser instance. + */ + param_spec = g_param_spec_object ("connection", + "TpConnection", + "TpConnection whose avatar should be " "shown and modified by this widget", - MC_TYPE_ACCOUNT, + TP_TYPE_CONNECTION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, - PROP_ACCOUNT, + PROP_CONNECTION, param_spec); g_type_class_add_private (object_class, sizeof (EmpathyAvatarChooserPriv)); @@ -214,8 +243,6 @@ empathy_avatar_chooser_init (EmpathyAvatarChooser *chooser) G_CALLBACK (avatar_chooser_clicked_cb), chooser); - priv->contact_factory = empathy_contact_factory_dup_singleton (); - empathy_avatar_chooser_set (chooser, NULL); } @@ -226,11 +253,9 @@ avatar_chooser_finalize (GObject *object) priv = GET_PRIV (object); - avatar_chooser_set_account (EMPATHY_AVATAR_CHOOSER (object), NULL); - g_assert (priv->account == NULL); - g_assert (priv->tp_contact_factory == NULL); - - g_object_unref (priv->contact_factory); + avatar_chooser_set_connection (EMPATHY_AVATAR_CHOOSER (object), NULL); + g_assert (priv->connection == NULL); + g_assert (priv->factory == NULL); if (priv->avatar != NULL) { empathy_avatar_unref (priv->avatar); @@ -240,51 +265,22 @@ avatar_chooser_finalize (GObject *object) } static void -avatar_chooser_tp_cf_ready_cb (EmpathyTpContactFactory *tp_cf, - GParamSpec *unused, - EmpathyAvatarChooser *self) -{ - EmpathyAvatarChooserPriv *priv = GET_PRIV (self); - gboolean ready; - - /* sanity check that we're listening on the right ETpCF */ - g_assert (priv->tp_contact_factory == tp_cf); - - ready = empathy_tp_contact_factory_is_ready (tp_cf); - gtk_widget_set_sensitive (GTK_WIDGET (self), ready); -} - -static void -avatar_chooser_set_account (EmpathyAvatarChooser *self, - McAccount *account) +avatar_chooser_set_connection (EmpathyAvatarChooser *self, + TpConnection *connection) { EmpathyAvatarChooserPriv *priv = GET_PRIV (self); - if (priv->account != NULL) { - g_object_unref (priv->account); - priv->account = NULL; + if (priv->connection != NULL) { + g_object_unref (priv->connection); + priv->connection = NULL; - g_assert (priv->tp_contact_factory != NULL); - - g_signal_handler_disconnect (priv->tp_contact_factory, - priv->ready_handler_id); - priv->ready_handler_id = 0; - - g_object_unref (priv->tp_contact_factory); - priv->tp_contact_factory = NULL; + g_object_unref (priv->factory); + priv->factory = NULL; } - if (account != NULL) { - priv->account = g_object_ref (account); - priv->tp_contact_factory = g_object_ref ( - empathy_contact_factory_get_tp_factory ( - priv->contact_factory, priv->account)); - - priv->ready_handler_id = g_signal_connect ( - priv->tp_contact_factory, "notify::ready", - G_CALLBACK (avatar_chooser_tp_cf_ready_cb), self); - avatar_chooser_tp_cf_ready_cb (priv->tp_contact_factory, NULL, - self); + if (connection != NULL) { + priv->connection = g_object_ref (connection); + priv->factory = empathy_tp_contact_factory_dup_singleton (connection); } } @@ -412,7 +408,6 @@ avatar_chooser_maybe_convert_and_scale (EmpathyAvatarChooser *chooser, EmpathyAvatar *avatar) { EmpathyAvatarChooserPriv *priv = GET_PRIV (chooser); - EmpathyTpContactFactory *tp_cf = priv->tp_contact_factory; guint max_width = 0, max_height = 0, max_size = 0; gchar **mime_types = NULL; gboolean needs_conversion = FALSE; @@ -424,15 +419,7 @@ avatar_chooser_maybe_convert_and_scale (EmpathyAvatarChooser *chooser, gchar *converted_image_data = NULL; gsize converted_image_size = 0; - /* This should only be called if the user is setting a new avatar, - * which should only be allowed once the avatar requirements have been - * discovered. - */ - g_return_val_if_fail (tp_cf != NULL, NULL); - g_return_val_if_fail (empathy_tp_contact_factory_is_ready (tp_cf), - NULL); - - g_object_get (tp_cf, + g_object_get (priv->factory, "avatar-mime-types", &mime_types, /* Needs g_strfreev-ing */ "avatar-max-width", &max_width, "avatar-max-height", &max_height, @@ -901,16 +888,6 @@ avatar_chooser_response_cb (GtkWidget *widget, priv->chooser_dialog = NULL; - if (response == GTK_RESPONSE_CANCEL) { - goto out; - } - - /* Check if we went non-ready since displaying the dialog. */ - if (!empathy_tp_contact_factory_is_ready (priv->tp_contact_factory)) { - DEBUG ("Can't set avatar when contact factory isn't ready."); - goto out; - } - if (response == GTK_RESPONSE_OK) { gchar *filename; gchar *path; @@ -932,7 +909,6 @@ avatar_chooser_response_cb (GtkWidget *widget, avatar_chooser_clear_image (chooser); } -out: gtk_widget_destroy (widget); } @@ -1037,12 +1013,26 @@ avatar_chooser_clicked_cb (GtkWidget *button, g_free (saved_dir); } +/** + * empathy_avatar_chooser_new: + * + * Creates a new #EmpathyAvatarChooser. + * + * Return value: a new #EmpathyAvatarChooser + */ GtkWidget * empathy_avatar_chooser_new () { return g_object_new (EMPATHY_TYPE_AVATAR_CHOOSER, NULL); } +/** + * empathy_avatar_chooser_set: + * @chooser: an #EmpathyAvatarChooser + * @avatar: a new #EmpathyAvatar + * + * Sets the @chooser to display the avatar indicated by @avatar. + */ void empathy_avatar_chooser_set (EmpathyAvatarChooser *chooser, EmpathyAvatar *avatar) @@ -1056,6 +1046,15 @@ empathy_avatar_chooser_set (EmpathyAvatarChooser *chooser, } } +/** + * empathy_avatar_chooser_get_image_data: + * @chooser: an #EmpathyAvatarChooser + * @data: avatar bytes + * @data_size: size of @data + * @mime_type: avatar mime-type + * + * Gets image data about the currently selected avatar. + */ void empathy_avatar_chooser_get_image_data (EmpathyAvatarChooser *chooser, const gchar **data, diff --git a/libempathy-gtk/empathy-avatar-chooser.h b/libempathy-gtk/empathy-avatar-chooser.h index bdc5b40a..564c1f37 100644 --- a/libempathy-gtk/empathy-avatar-chooser.h +++ b/libempathy-gtk/empathy-avatar-chooser.h @@ -41,6 +41,8 @@ typedef struct _EmpathyAvatarChooserClass EmpathyAvatarChooserClass; struct _EmpathyAvatarChooser { GtkButton parent; + + /**/ gpointer priv; }; diff --git a/libempathy-gtk/empathy-avatar-image.c b/libempathy-gtk/empathy-avatar-image.c index 51f30bdd..e5513231 100644 --- a/libempathy-gtk/empathy-avatar-image.c +++ b/libempathy-gtk/empathy-avatar-image.c @@ -33,6 +33,22 @@ #include "empathy-avatar-image.h" #include "empathy-ui-utils.h" +/** + * SECTION:empathy-avatar-image + * @title: EmpathyAvatarImage + * @short_description: A widget to display an avatar + * @include: libempathy-gtk/empathy-avatar-image.h + * + * #EmpathyAvatarImage is a widget which displays an avatar. + */ + +/** + * EmpathyAvatarImage: + * @parent: parent object + * + * Widget which displays an avatar. + */ + #define MAX_SMALL 64 #define MAX_LARGE 400 @@ -251,6 +267,13 @@ avatar_image_button_release_event (GtkWidget *widget, GdkEventButton *event) return TRUE; } +/** + * empathy_avatar_image_new: + * + * Creates a new #EmpathyAvatarImage. + * + * Return value: a new #EmpathyAvatarImage + */ GtkWidget * empathy_avatar_image_new (void) { @@ -261,6 +284,13 @@ empathy_avatar_image_new (void) return GTK_WIDGET (avatar_image); } +/** + * empathy_avatar_image_set: + * @avatar_image: an #EmpathyAvatarImage + * @avatar: the #EmpathyAvatar to set @avatar_image to + * + * Sets @avatar_image to display the avatar indicated by @avatar. + */ void empathy_avatar_image_set (EmpathyAvatarImage *avatar_image, EmpathyAvatar *avatar) diff --git a/libempathy-gtk/empathy-avatar-image.h b/libempathy-gtk/empathy-avatar-image.h index d6a6cd0b..8969c122 100644 --- a/libempathy-gtk/empathy-avatar-image.h +++ b/libempathy-gtk/empathy-avatar-image.h @@ -42,6 +42,8 @@ typedef struct _EmpathyAvatarImageClass EmpathyAvatarImageClass; struct _EmpathyAvatarImage { GtkEventBox parent; + + /**/ gpointer priv; }; diff --git a/libempathy-gtk/empathy-chat.c b/libempathy-gtk/empathy-chat.c index 7d939027..425a1c55 100644 --- a/libempathy-gtk/empathy-chat.c +++ b/libempathy-gtk/empathy-chat.c @@ -45,7 +45,6 @@ #include "empathy-chat.h" #include "empathy-conf.h" #include "empathy-spell.h" -#include "empathy-spell-dialog.h" #include "empathy-contact-list-store.h" #include "empathy-contact-list-view.h" #include "empathy-contact-menu.h" @@ -65,7 +64,6 @@ #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyChat) typedef struct { EmpathyTpChat *tp_chat; - gulong tp_chat_destroy_handler; McAccount *account; gchar *id; gchar *name; @@ -190,17 +188,15 @@ chat_connect_channel_reconnected (EmpathyDispatchOperation *dispatch, } static void -chat_connection_changed_cb (EmpathyAccountManager *manager, - McAccount *account, - TpConnectionStatusReason reason, - TpConnectionStatus current, - TpConnectionStatus previous, - EmpathyChat *chat) +chat_new_connection_cb (EmpathyAccountManager *manager, + TpConnection *connection, + EmpathyChat *chat) { EmpathyChatPriv *priv = GET_PRIV (chat); + McAccount *account; - if (current == TP_CONNECTION_STATUS_CONNECTED && !priv->tp_chat && - empathy_account_equal (account, priv->account) && + account = empathy_account_manager_get_account (manager, connection); + if (!priv->tp_chat && empathy_account_equal (account, priv->account) && priv->handle_type != TP_HANDLE_TYPE_NONE && !EMP_STR_EMPTY (priv->id)) { @@ -208,12 +204,14 @@ chat_connection_changed_cb (EmpathyAccountManager *manager, switch (priv->handle_type) { case TP_HANDLE_TYPE_CONTACT: - empathy_dispatcher_chat_with_contact_id (account, priv->id, + empathy_dispatcher_chat_with_contact_id ( + connection, priv->id, chat_connect_channel_reconnected, chat); break; case TP_HANDLE_TYPE_ROOM: - empathy_dispatcher_join_muc (account, priv->id, + empathy_dispatcher_join_muc (connection, + priv->id, chat_connect_channel_reconnected, chat); break; @@ -596,7 +594,7 @@ chat_property_changed_cb (EmpathyTpChat *tp_chat, static void chat_input_text_buffer_changed_cb (GtkTextBuffer *buffer, - EmpathyChat *chat) + EmpathyChat *chat) { EmpathyChatPriv *priv; GtkTextIter start, end; @@ -612,8 +610,8 @@ chat_input_text_buffer_changed_cb (GtkTextBuffer *buffer, } empathy_conf_get_bool (empathy_conf_get (), - EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED, - &spell_checker); + EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED, + &spell_checker); gtk_text_buffer_get_start_iter (buffer, &start); @@ -932,13 +930,42 @@ chat_spell_free (EmpathyChatSpell *chat_spell) } static void -chat_text_check_word_spelling_cb (GtkMenuItem *menuitem, - EmpathyChatSpell *chat_spell) +chat_spelling_menu_activate_cb (GtkMenuItem *menu_item, + EmpathyChatSpell *chat_spell) { - empathy_spell_dialog_show (chat_spell->chat, - &chat_spell->start, - &chat_spell->end, - chat_spell->word); + empathy_chat_correct_word (chat_spell->chat, + &(chat_spell->start), + &(chat_spell->end), + gtk_menu_item_get_label (menu_item)); +} + +static GtkWidget* +chat_spelling_build_menu (EmpathyChatSpell *chat_spell) +{ + GtkWidget *menu, *menu_item; + GList *suggestions, *l; + + menu = gtk_menu_new (); + suggestions = empathy_spell_get_suggestions (chat_spell->word); + if (suggestions == NULL) { + menu_item = gtk_menu_item_new_with_label (_("(No Suggestions)")); + gtk_widget_set_sensitive (menu_item, FALSE); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); + } else { + for (l = suggestions; l; l = l->next) { + menu_item = gtk_menu_item_new_with_label (l->data); + g_signal_connect (G_OBJECT (menu_item), + "activate", + G_CALLBACK (chat_spelling_menu_activate_cb), + chat_spell); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); + } + } + empathy_spell_free_suggestions (suggestions); + + gtk_widget_show_all (menu); + + return menu; } static void @@ -961,7 +988,8 @@ chat_input_populate_popup_cb (GtkTextView *view, GtkTextIter iter, start, end; GtkWidget *item; gchar *str = NULL; - EmpathyChatSpell *chat_spell; + EmpathyChatSpell *chat_spell; + GtkWidget *spell_menu; EmpathySmileyManager *smiley_manager; GtkWidget *smiley_menu; GtkWidget *image; @@ -1026,14 +1054,14 @@ chat_input_populate_popup_cb (GtkTextView *view, gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); - item = gtk_image_menu_item_new_with_mnemonic (_("_Check Word Spelling...")); + item = gtk_image_menu_item_new_with_mnemonic (_("_Spelling Suggestions")); image = gtk_image_new_from_icon_name (GTK_STOCK_SPELL_CHECK, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); - g_signal_connect (item, - "activate", - G_CALLBACK (chat_text_check_word_spelling_cb), - chat_spell); + + spell_menu = chat_spelling_build_menu (chat_spell); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), spell_menu); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); } @@ -1139,10 +1167,6 @@ chat_members_changed_cb (EmpathyTpChat *tp_chat, if (priv->block_events_timeout_id == 0) { gchar *str; - empathy_contact_run_until_ready (contact, - EMPATHY_CONTACT_READY_NAME, - NULL); - if (is_member) { str = g_strdup_printf (_("%s has joined the room"), empathy_contact_get_name (contact)); @@ -1434,13 +1458,26 @@ chat_finalize (GObject *object) chat_composing_remove_timeout (chat); g_signal_handlers_disconnect_by_func (priv->account_manager, - chat_connection_changed_cb, object); + chat_new_connection_cb, object); g_object_unref (priv->account_manager); g_object_unref (priv->log_manager); if (priv->tp_chat) { - g_signal_handler_disconnect (priv->tp_chat, priv->tp_chat_destroy_handler); + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_destroy_cb, chat); + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_message_received_cb, chat); + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_send_error_cb, chat); + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_state_changed_cb, chat); + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_property_changed_cb, chat); + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_members_changed_cb, chat); + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_remote_contact_changed_cb, chat); empathy_tp_chat_close (priv->tp_chat); g_object_unref (priv->tp_chat); } @@ -1578,8 +1615,8 @@ empathy_chat_init (EmpathyChat *chat) priv->account_manager = empathy_account_manager_dup_singleton (); g_signal_connect (priv->account_manager, - "account-connection-changed", - G_CALLBACK (chat_connection_changed_cb), + "new-connection", + G_CALLBACK (chat_new_connection_cb), chat); /* Block events for some time to avoid having "has come online" or @@ -1613,6 +1650,7 @@ empathy_chat_set_tp_chat (EmpathyChat *chat, EmpathyTpChat *tp_chat) { EmpathyChatPriv *priv = GET_PRIV (chat); + TpConnection *connection; g_return_if_fail (EMPATHY_IS_CHAT (chat)); g_return_if_fail (EMPATHY_IS_TP_CHAT (tp_chat)); @@ -1627,8 +1665,14 @@ empathy_chat_set_tp_chat (EmpathyChat *chat, } priv->tp_chat = g_object_ref (tp_chat); - priv->account = g_object_ref (empathy_tp_chat_get_account (tp_chat)); + connection = empathy_tp_chat_get_connection (priv->tp_chat); + priv->account = empathy_account_manager_get_account (priv->account_manager, + connection); + g_object_ref (priv->account); + g_signal_connect (tp_chat, "destroy", + G_CALLBACK (chat_destroy_cb), + chat); g_signal_connect (tp_chat, "message-received", G_CALLBACK (chat_message_received_cb), chat); @@ -1647,10 +1691,6 @@ empathy_chat_set_tp_chat (EmpathyChat *chat, g_signal_connect_swapped (tp_chat, "notify::remote-contact", G_CALLBACK (chat_remote_contact_changed_cb), chat); - priv->tp_chat_destroy_handler = - g_signal_connect (tp_chat, "destroy", - G_CALLBACK (chat_destroy_cb), - chat); chat_remote_contact_changed_cb (chat); @@ -1730,20 +1770,6 @@ empathy_chat_get_remote_contact (EmpathyChat *chat) return priv->remote_contact; } -guint -empathy_chat_get_members_count (EmpathyChat *chat) -{ - EmpathyChatPriv *priv = GET_PRIV (chat); - - g_return_val_if_fail (EMPATHY_IS_CHAT (chat), 0); - - if (priv->tp_chat) { - return empathy_tp_chat_get_members_count (priv->tp_chat); - } - - return 0; -} - GtkWidget * empathy_chat_get_contact_menu (EmpathyChat *chat) { diff --git a/libempathy-gtk/empathy-chat.h b/libempathy-gtk/empathy-chat.h index 6b7fcf26..f61ce415 100644 --- a/libempathy-gtk/empathy-chat.h +++ b/libempathy-gtk/empathy-chat.h @@ -71,7 +71,6 @@ const gchar * empathy_chat_get_id (EmpathyChat *chat); const gchar * empathy_chat_get_name (EmpathyChat *chat); const gchar * empathy_chat_get_subject (EmpathyChat *chat); EmpathyContact * empathy_chat_get_remote_contact (EmpathyChat *chat); -guint empathy_chat_get_members_count (EmpathyChat *chat); GtkWidget * empathy_chat_get_contact_menu (EmpathyChat *chat); void empathy_chat_clear (EmpathyChat *chat); void empathy_chat_scroll_down (EmpathyChat *chat); diff --git a/libempathy-gtk/empathy-contact-dialogs.c b/libempathy-gtk/empathy-contact-dialogs.c index 72b5b28b..056ec2d8 100644 --- a/libempathy-gtk/empathy-contact-dialogs.c +++ b/libempathy-gtk/empathy-contact-dialogs.c @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -39,9 +40,10 @@ static GList *subscription_dialogs = NULL; static GList *information_dialogs = NULL; +static GList *edit_dialogs = NULL; +static GtkWidget *personal_dialog = NULL; static GtkWidget *new_contact_dialog = NULL; - static gint contact_dialogs_find (GtkDialog *dialog, EmpathyContact *contact) @@ -114,6 +116,7 @@ empathy_subscription_dialog_show (EmpathyContact *contact, g_free (filename); g_object_unref (gui); + /* Contact info widget */ contact_widget = empathy_contact_widget_new (contact, EMPATHY_CONTACT_WIDGET_EDIT_ALIAS | EMPATHY_CONTACT_WIDGET_EDIT_GROUPS); @@ -123,7 +126,6 @@ empathy_subscription_dialog_show (EmpathyContact *contact, 0); gtk_widget_show (contact_widget); - g_object_set_data (G_OBJECT (dialog), "contact_widget", contact_widget); subscription_dialogs = g_list_prepend (subscription_dialogs, dialog); @@ -143,25 +145,22 @@ empathy_subscription_dialog_show (EmpathyContact *contact, */ static void -contact_information_response_cb (GtkDialog *dialog, - gint response, - GtkWidget *contact_widget) +contact_dialogs_response_cb (GtkDialog *dialog, + gint response, + GList **dialogs) { - information_dialogs = g_list_remove (information_dialogs, dialog); + *dialogs = g_list_remove (*dialogs, dialog); gtk_widget_destroy (GTK_WIDGET (dialog)); } void empathy_contact_information_dialog_show (EmpathyContact *contact, - GtkWindow *parent, - gboolean edit, - gboolean is_user) + GtkWindow *parent) { - GtkWidget *dialog; - GtkWidget *button; - GtkWidget *contact_widget; - GList *l; - EmpathyContactWidgetFlags flags = 0; + GtkWidget *dialog; + GtkWidget *button; + GtkWidget *contact_widget; + GList *l; g_return_if_fail (EMPATHY_IS_CONTACT (contact)); @@ -177,15 +176,7 @@ empathy_contact_information_dialog_show (EmpathyContact *contact, dialog = gtk_dialog_new (); gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); - if (is_user) { - gtk_window_set_title (GTK_WINDOW (dialog), _("Personal Information")); - } - else if (edit) { - gtk_window_set_title (GTK_WINDOW (dialog), _("Edit Contact Information")); - } - else { - gtk_window_set_title (GTK_WINDOW (dialog), _("Contact Information")); - } + gtk_window_set_title (GTK_WINDOW (dialog), _("Edit Contact Information")); /* Close button */ button = gtk_button_new_with_label (GTK_STOCK_CLOSE); @@ -198,34 +189,79 @@ empathy_contact_information_dialog_show (EmpathyContact *contact, gtk_widget_show (button); /* Contact info widget */ - if (edit) { - flags |= EMPATHY_CONTACT_WIDGET_EDIT_ALIAS; - } - if (is_user) { - flags |= EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT; - flags |= EMPATHY_CONTACT_WIDGET_EDIT_AVATAR; + contact_widget = empathy_contact_widget_new (contact, + EMPATHY_CONTACT_WIDGET_EDIT_NONE); + gtk_container_set_border_width (GTK_CONTAINER (contact_widget), 8); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), + contact_widget, + TRUE, TRUE, 0); + gtk_widget_show (contact_widget); + + g_object_set_data (G_OBJECT (dialog), "contact_widget", contact_widget); + information_dialogs = g_list_prepend (information_dialogs, dialog); + + g_signal_connect (dialog, "response", + G_CALLBACK (contact_dialogs_response_cb), + &information_dialogs); + + if (parent) { + gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); } - if (!is_user && edit) { - flags |= EMPATHY_CONTACT_WIDGET_EDIT_GROUPS; + + gtk_widget_show (dialog); +} + +void +empathy_contact_edit_dialog_show (EmpathyContact *contact, + GtkWindow *parent) +{ + GtkWidget *dialog; + GtkWidget *button; + GtkWidget *contact_widget; + GList *l; + + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + + l = g_list_find_custom (edit_dialogs, + contact, + (GCompareFunc) contact_dialogs_find); + if (l) { + gtk_window_present (GTK_WINDOW (l->data)); + return; } - contact_widget = empathy_contact_widget_new (contact, flags); + + /* Create dialog */ + dialog = gtk_dialog_new (); + gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); + gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); + gtk_window_set_title (GTK_WINDOW (dialog), _("Edit Contact Information")); + + /* Close button */ + button = gtk_button_new_with_label (GTK_STOCK_CLOSE); + gtk_button_set_use_stock (GTK_BUTTON (button), TRUE); + gtk_dialog_add_action_widget (GTK_DIALOG (dialog), + button, + GTK_RESPONSE_CLOSE); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_window_set_default (GTK_WINDOW (dialog), button); + gtk_widget_show (button); + + /* Contact info widget */ + contact_widget = empathy_contact_widget_new (contact, + EMPATHY_CONTACT_WIDGET_EDIT_ALIAS | + EMPATHY_CONTACT_WIDGET_EDIT_GROUPS); gtk_container_set_border_width (GTK_CONTAINER (contact_widget), 8); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), contact_widget, TRUE, TRUE, 0); - if (flags & EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT) { - empathy_contact_widget_set_account_filter (contact_widget, - empathy_account_chooser_filter_is_connected, - NULL); - } gtk_widget_show (contact_widget); g_object_set_data (G_OBJECT (dialog), "contact_widget", contact_widget); - information_dialogs = g_list_prepend (information_dialogs, dialog); + edit_dialogs = g_list_prepend (edit_dialogs, dialog); g_signal_connect (dialog, "response", - G_CALLBACK (contact_information_response_cb), - contact_widget); + G_CALLBACK (contact_dialogs_response_cb), + &edit_dialogs); if (parent) { gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); @@ -234,6 +270,58 @@ empathy_contact_information_dialog_show (EmpathyContact *contact, gtk_widget_show (dialog); } +void +empathy_contact_personal_dialog_show (GtkWindow *parent) +{ + GtkWidget *button; + GtkWidget *contact_widget; + + if (personal_dialog) { + gtk_window_present (GTK_WINDOW (personal_dialog)); + return; + } + + /* Create dialog */ + personal_dialog = gtk_dialog_new (); + gtk_dialog_set_has_separator (GTK_DIALOG (personal_dialog), FALSE); + gtk_window_set_resizable (GTK_WINDOW (personal_dialog), FALSE); + gtk_window_set_title (GTK_WINDOW (personal_dialog), _("Personal Information")); + + /* Close button */ + button = gtk_button_new_with_label (GTK_STOCK_CLOSE); + gtk_button_set_use_stock (GTK_BUTTON (button), TRUE); + gtk_dialog_add_action_widget (GTK_DIALOG (personal_dialog), + button, + GTK_RESPONSE_CLOSE); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_window_set_default (GTK_WINDOW (personal_dialog), button); + gtk_widget_show (button); + + /* Contact info widget */ + contact_widget = empathy_contact_widget_new (NULL, + EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT | + EMPATHY_CONTACT_WIDGET_EDIT_ALIAS | + EMPATHY_CONTACT_WIDGET_EDIT_AVATAR); + gtk_container_set_border_width (GTK_CONTAINER (contact_widget), 8); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (personal_dialog)->vbox), + contact_widget, + TRUE, TRUE, 0); + empathy_contact_widget_set_account_filter (contact_widget, + empathy_account_chooser_filter_is_connected, NULL); + gtk_widget_show (contact_widget); + + g_signal_connect (personal_dialog, "response", + G_CALLBACK (gtk_widget_destroy), NULL); + g_object_add_weak_pointer (G_OBJECT (personal_dialog), + (gpointer) &personal_dialog); + + if (parent) { + gtk_window_set_transient_for (GTK_WINDOW (personal_dialog), parent); + } + + gtk_widget_show (personal_dialog); +} + /* * New contact dialog */ @@ -242,12 +330,23 @@ static gboolean can_add_contact_to_account (McAccount *account, gpointer user_data) { - EmpathyContactManager *mgr; + EmpathyAccountManager *account_manager; + EmpathyContactManager *contact_manager; + TpConnection *connection; gboolean result; - mgr = empathy_contact_manager_dup_singleton (); - result = empathy_contact_manager_can_add (mgr, account); - g_object_unref (mgr); + account_manager = empathy_account_manager_dup_singleton (); + connection = empathy_account_manager_get_connection (account_manager, + account); + if (!connection) { + g_object_unref (account_manager); + return FALSE; + } + + contact_manager = empathy_contact_manager_dup_singleton (); + result = empathy_contact_manager_can_add (contact_manager, connection); + g_object_unref (contact_manager); + g_object_unref (account_manager); return result; } diff --git a/libempathy-gtk/empathy-contact-dialogs.h b/libempathy-gtk/empathy-contact-dialogs.h index e375f959..c714c6b9 100644 --- a/libempathy-gtk/empathy-contact-dialogs.h +++ b/libempathy-gtk/empathy-contact-dialogs.h @@ -29,12 +29,13 @@ G_BEGIN_DECLS void empathy_subscription_dialog_show (EmpathyContact *contact, - GtkWindow *parent); + GtkWindow *parent); void empathy_contact_information_dialog_show (EmpathyContact *contact, - GtkWindow *parent, - gboolean edit, - gboolean is_user); -void empathy_new_contact_dialog_show (GtkWindow *parent); + GtkWindow *parent); +void empathy_contact_edit_dialog_show (EmpathyContact *contact, + GtkWindow *parent); +void empathy_contact_personal_dialog_show (GtkWindow *parent); +void empathy_new_contact_dialog_show (GtkWindow *parent); G_END_DECLS diff --git a/libempathy-gtk/empathy-contact-list-view.c b/libempathy-gtk/empathy-contact-list-view.c index 3fdc7b32..ca224f52 100644 --- a/libempathy-gtk/empathy-contact-list-view.c +++ b/libempathy-gtk/empathy-contact-list-view.c @@ -31,10 +31,12 @@ #include #include +#include #include +#include #include -#include +#include #include #include #include @@ -122,8 +124,8 @@ contact_list_view_tooltip_destroy_cb (GtkWidget *widget, if (priv->tooltip_widget) { DEBUG ("Tooltip destroyed"); + g_object_unref (priv->tooltip_widget); priv->tooltip_widget = NULL; - g_object_unref (widget); } } @@ -188,8 +190,52 @@ OUT: return ret; } +typedef struct { + gchar *new_group; + gchar *old_group; + GdkDragAction action; +} DndGetContactData; + +static void +contact_list_view_dnd_get_contact_free (DndGetContactData *data) +{ + g_free (data->new_group); + g_free (data->old_group); + g_slice_free (DndGetContactData, data); +} + static void -contact_list_view_drag_data_received (GtkWidget *widget, +contact_list_view_drag_got_contact (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *view) +{ + EmpathyContactListViewPriv *priv = GET_PRIV (view); + DndGetContactData *data = user_data; + EmpathyContactList *list; + + if (error != NULL) { + DEBUG ("Error: %s", error->message); + return; + } + + DEBUG ("contact %s (%d) dragged from '%s' to '%s'", + empathy_contact_get_id (contact), + empathy_contact_get_handle (contact), + data->old_group, data->new_group); + + list = empathy_contact_list_store_get_list_iface (priv->store); + if (data->new_group) { + empathy_contact_list_add_to_group (list, contact, data->new_group); + } + if (data->old_group && data->action == GDK_ACTION_MOVE) { + empathy_contact_list_remove_from_group (list, contact, data->old_group); + } +} + +static void +contact_list_view_drag_data_received (GtkWidget *view, GdkDragContext *context, gint x, gint y, @@ -198,88 +244,102 @@ contact_list_view_drag_data_received (GtkWidget *widget, guint time) { EmpathyContactListViewPriv *priv; - EmpathyContactList *list; - EmpathyContactFactory *factory; + EmpathyAccountManager *account_manager; + EmpathyTpContactFactory *factory = NULL; McAccount *account; GtkTreeModel *model; - GtkTreePath *path; GtkTreeViewDropPosition position; - EmpathyContact *contact = NULL; + GtkTreePath *path; const gchar *id; - gchar **strv; + gchar **strv = NULL; + const gchar *account_id; + const gchar *contact_id; gchar *new_group = NULL; gchar *old_group = NULL; + DndGetContactData *data; gboolean is_row; + gboolean success = TRUE; - priv = GET_PRIV (widget); - - id = (const gchar*) selection->data; - DEBUG ("Received %s%s drag & drop contact from roster with id:'%s'", - context->action == GDK_ACTION_MOVE ? "move" : "", - context->action == GDK_ACTION_COPY ? "copy" : "", - id); + priv = GET_PRIV (view); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); - strv = g_strsplit (id, "/", 2); - factory = empathy_contact_factory_dup_singleton (); - account = mc_account_lookup (strv[0]); - if (account) { - contact = empathy_contact_factory_get_from_id (factory, - account, - strv[1]); - g_object_unref (account); - } - g_object_unref (factory); - g_strfreev (strv); + /* Get destination group information. */ + is_row = gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (view), + x, + y, + &path, + &position); - if (!contact) { - DEBUG ("No contact found associated with drag & drop"); - return; + if (is_row) { + new_group = empathy_contact_list_store_get_parent_group (model, + path, NULL); + gtk_tree_path_free (path); } - empathy_contact_run_until_ready (contact, - EMPATHY_CONTACT_READY_HANDLE, - NULL); - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); - /* Get source group information. */ if (priv->drag_row) { path = gtk_tree_row_reference_get_path (priv->drag_row); if (path) { - old_group = empathy_contact_list_store_get_parent_group (model, path, NULL); + old_group = empathy_contact_list_store_get_parent_group ( + model, path, NULL); gtk_tree_path_free (path); } } - /* Get destination group information. */ - is_row = gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget), - x, - y, - &path, - &position); - - if (is_row) { - new_group = empathy_contact_list_store_get_parent_group (model, path, NULL); - gtk_tree_path_free (path); + if (!tp_strdiff (old_group, new_group)) { + g_free (new_group); + g_free (old_group); + goto OUT; } - DEBUG ("contact %s (%d) dragged from '%s' to '%s'", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - old_group, new_group); + id = (const gchar*) selection->data; + DEBUG ("Received %s%s drag & drop contact from roster with id:'%s'", + context->action == GDK_ACTION_MOVE ? "move" : "", + context->action == GDK_ACTION_COPY ? "copy" : "", + id); - list = empathy_contact_list_store_get_list_iface (priv->store); - if (new_group) { - empathy_contact_list_add_to_group (list, contact, new_group); + strv = g_strsplit (id, "/", 2); + account_id = strv[0]; + contact_id = strv[1]; + account = mc_account_lookup (account_id); + if (account) { + TpConnection *connection; + + /* FIXME: We assume we have already an account manager */ + account_manager = empathy_account_manager_dup_singleton (); + connection = empathy_account_manager_get_connection (account_manager, + account); + if (connection) { + factory = empathy_tp_contact_factory_dup_singleton (connection); + } + g_object_unref (account_manager); } - if (old_group && context->action == GDK_ACTION_MOVE) { - empathy_contact_list_remove_from_group (list, contact, old_group); + + if (!factory) { + DEBUG ("Failed to get factory for account '%s'", account_id); + success = FALSE; + g_free (new_group); + g_free (old_group); + goto OUT; } - g_free (old_group); - g_free (new_group); + data = g_slice_new0 (DndGetContactData); + data->new_group = new_group; + data->old_group = old_group; + data->action = context->action; - gtk_drag_finish (context, TRUE, FALSE, GDK_CURRENT_TIME); + /* FIXME: We should probably wait for the cb before calling + * gtk_drag_finish */ + empathy_tp_contact_factory_get_from_id (factory, contact_id, + contact_list_view_drag_got_contact, + data, (GDestroyNotify) contact_list_view_dnd_get_contact_free, + G_OBJECT (view)); + + g_object_unref (factory); + +OUT: + g_strfreev (strv); + gtk_drag_finish (context, success, FALSE, GDK_CURRENT_TIME); } static gboolean @@ -414,7 +474,7 @@ contact_list_view_drag_data_get (GtkWidget *widget, gtk_tree_path_free (src_path); - contact = empathy_contact_list_view_get_selected (EMPATHY_CONTACT_LIST_VIEW (widget)); + contact = empathy_contact_list_view_dup_selected (EMPATHY_CONTACT_LIST_VIEW (widget)); if (!contact) { return; } @@ -1158,7 +1218,7 @@ empathy_contact_list_view_new (EmpathyContactListStore *store, } EmpathyContact * -empathy_contact_list_view_get_selected (EmpathyContactListView *view) +empathy_contact_list_view_dup_selected (EmpathyContactListView *view) { EmpathyContactListViewPriv *priv; GtkTreeSelection *selection; @@ -1324,7 +1384,7 @@ contact_list_view_remove_activate_cb (GtkMenuItem *menuitem, EmpathyContactListViewPriv *priv = GET_PRIV (view); EmpathyContact *contact; - contact = empathy_contact_list_view_get_selected (view); + contact = empathy_contact_list_view_dup_selected (view); if (contact) { gchar *text; @@ -1357,7 +1417,7 @@ empathy_contact_list_view_get_contact_menu (EmpathyContactListView *view) g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view), NULL); - contact = empathy_contact_list_view_get_selected (view); + contact = empathy_contact_list_view_dup_selected (view); if (!contact) { return NULL; } diff --git a/libempathy-gtk/empathy-contact-list-view.h b/libempathy-gtk/empathy-contact-list-view.h index 82990d64..bb6766c4 100644 --- a/libempathy-gtk/empathy-contact-list-view.h +++ b/libempathy-gtk/empathy-contact-list-view.h @@ -70,7 +70,7 @@ GType empathy_contact_list_view_get_type (void) G EmpathyContactListView * empathy_contact_list_view_new (EmpathyContactListStore *store, EmpathyContactListFeatureFlags list_features, EmpathyContactFeatureFlags contact_features); -EmpathyContact * empathy_contact_list_view_get_selected (EmpathyContactListView *view); +EmpathyContact * empathy_contact_list_view_dup_selected (EmpathyContactListView *view); gchar * empathy_contact_list_view_get_selected_group (EmpathyContactListView *view); GtkWidget * empathy_contact_list_view_get_contact_menu (EmpathyContactListView *view); GtkWidget * empathy_contact_list_view_get_group_menu (EmpathyContactListView *view); diff --git a/libempathy-gtk/empathy-contact-menu.c b/libempathy-gtk/empathy-contact-menu.c index 9cd9a0b9..a3cf1da2 100644 --- a/libempathy-gtk/empathy-contact-menu.c +++ b/libempathy-gtk/empathy-contact-menu.c @@ -236,7 +236,7 @@ empathy_contact_file_transfer_menu_item_new (EmpathyContact *contact) static void contact_info_menu_item_activate_cb (EmpathyContact *contact) { - empathy_contact_information_dialog_show (contact, NULL, FALSE, FALSE); + empathy_contact_information_dialog_show (contact, NULL); } GtkWidget * @@ -263,7 +263,7 @@ empathy_contact_info_menu_item_new (EmpathyContact *contact) static void contact_edit_menu_item_activate_cb (EmpathyContact *contact) { - empathy_contact_information_dialog_show (contact, NULL, TRUE, FALSE); + empathy_contact_edit_dialog_show (contact, NULL); } GtkWidget * diff --git a/libempathy-gtk/empathy-contact-selector.c b/libempathy-gtk/empathy-contact-selector.c index 539629a2..f4a302c5 100644 --- a/libempathy-gtk/empathy-contact-selector.c +++ b/libempathy-gtk/empathy-contact-selector.c @@ -31,6 +31,23 @@ #include "empathy-contact-selector.h" +/** + * SECTION:empathy-contact-selector + * @title:EmpathyContactSelector + * @short_description: A widget used to choose from a list of contacts. + * @include: libempathy-gtk/empathy-contact-selector.h + * + * #EmpathyContactSelector is a widget which extends #GtkComboBox to provide + * a chooser of available contacts. + */ + +/** + * EmpathyContactSelector: + * @parent: parent object + * + * Widget which extends #GtkComboBox to provide a chooser of available contacts. + */ + G_DEFINE_TYPE (EmpathyContactSelector, empathy_contact_selector, GTK_TYPE_COMBO_BOX) @@ -320,14 +337,27 @@ empathy_contact_selector_class_init (EmpathyContactSelectorClass *klass) object_class->get_property = contact_selector_get_property; g_type_class_add_private (klass, sizeof (EmpathyContactSelectorPriv)); + /** + * EmpathyContactSelector:contact-list: + * + * An #EmpathyContactList containing the contacts for the + * #EmpathyContactSelector. + */ g_object_class_install_property (object_class, PROP_CONTACT_LIST, g_param_spec_object ("contact-list", "contact list", "contact list", EMPATHY_TYPE_CONTACT_LIST, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); } -/* public methods */ - +/** + * empathy_contact_selector_new: + * @contact_list: an #EmpathyContactList containing the contacts to list in + * the contact selector + * + * Creates a new #EmpathyContactSelector. + * + * Return value: A new #EmpathyContactSelector + */ GtkWidget * empathy_contact_selector_new (EmpathyContactList *contact_list) { @@ -337,6 +367,16 @@ empathy_contact_selector_new (EmpathyContactList *contact_list) "contact-list", contact_list, NULL)); } +/** + * empathy_contact_selector_dup_selected: + * @selector: An #EmpathyContactSelector + * + * Returns a new reference to the contact which is currently selected in + * @selector, or %NULL if there is no contact selected. The returned contact + * should be unrefed with g_object_unref() when finished with. + * + * Return value: A new reference to the contact currently selected, or %NULL + */ EmpathyContact * empathy_contact_selector_dup_selected (EmpathyContactSelector *selector) { @@ -390,6 +430,19 @@ contact_selector_filter_visible_func (GtkTreeModel *model, return visible; } +/** + * empathy_contact_selector_set_visible: + * @selector: an #EmpathyContactSelector + * @func: an #EmpathyContactSelectorFilterFunc to filter the contacts + * @user_data: data to pass to @func or %NULL + * + * Sets a filter on the @selector so only contacts that return %TRUE + * when passed into @func are visible. + * + * A typical usage for this function would be to only show contacts that + * can send or receive files. In this case, one could use the + * empathy_contact_can_send_files() function + */ void empathy_contact_selector_set_visible (EmpathyContactSelector *selector, EmpathyContactSelectorFilterFunc func, @@ -407,3 +460,14 @@ empathy_contact_selector_set_visible (EmpathyContactSelector *selector, gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->model)); } + +/** + * EmpathyContactSelectorFilterFunc: + * @contact: an #EmpathyContact + * @user_data: user data or %NULL + * + * A function which decides whether the contact indicated by @contact + * is visible. + * + * Return value: whether @contact is visible + */ diff --git a/libempathy-gtk/empathy-contact-selector.h b/libempathy-gtk/empathy-contact-selector.h index f7af92f2..205b9e41 100644 --- a/libempathy-gtk/empathy-contact-selector.h +++ b/libempathy-gtk/empathy-contact-selector.h @@ -49,6 +49,8 @@ typedef struct _EmpathyContactSelectorClass EmpathyContactSelectorClass; struct _EmpathyContactSelector { GtkComboBox parent; + + /**/ gpointer priv; }; diff --git a/libempathy-gtk/empathy-contact-widget.c b/libempathy-gtk/empathy-contact-widget.c index ef259b0a..0821066f 100644 --- a/libempathy-gtk/empathy-contact-widget.c +++ b/libempathy-gtk/empathy-contact-widget.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include #include @@ -44,12 +44,31 @@ #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT #include +/** + * SECTION:empathy-contact-widget + * @title:EmpathyContactWidget + * @short_description: A widget used to display and edit details about a contact + * @include: libempathy-empathy-contact-widget.h + * + * #EmpathyContactWidget is a widget which displays appropriate widgets + * with details about a contact, also allowing changing these details, + * if desired. + */ + +/** + * EmpathyContactWidget: + * @parent: parent object + * + * Widget which displays appropriate widgets with details about a contact, + * also allowing changing these details, if desired. + */ + /* Delay before updating the widget when the id entry changed (seconds) */ #define ID_CHANGED_TIMEOUT 1 typedef struct { - EmpathyContactFactory *factory; + EmpathyTpContactFactory *factory; EmpathyContactManager *manager; EmpathyContact *contact; EmpathyContactWidgetFlags flags; @@ -106,8 +125,6 @@ static void contact_widget_contact_update (EmpathyContactWidget *information); static void contact_widget_change_contact (EmpathyContactWidget *information); static void contact_widget_avatar_changed_cb (EmpathyAvatarChooser *chooser, EmpathyContactWidget *information); -static void contact_widget_account_changed_cb (GtkComboBox *widget, - EmpathyContactWidget *information); static gboolean contact_widget_id_focus_out_cb (GtkWidget *widget, GdkEventFocus *event, EmpathyContactWidget *information); static gboolean contact_widget_entry_alias_focus_event_cb ( @@ -153,6 +170,15 @@ enum COL_COUNT }; +/** + * empathy_contact_widget_new: + * @contact: an #EmpathyContact + * @flags: #EmpathyContactWidgetFlags for the new contact widget + * + * Creates a new #EmpathyContactWidget. + * + * Return value: a new #EmpathyContactWidget + */ GtkWidget * empathy_contact_widget_new (EmpathyContact *contact, EmpathyContactWidgetFlags flags) @@ -161,9 +187,10 @@ empathy_contact_widget_new (EmpathyContact *contact, GtkBuilder *gui; gchar *filename; + g_return_val_if_fail (contact == NULL || EMPATHY_IS_CONTACT (contact), NULL); + information = g_slice_new0 (EmpathyContactWidget); information->flags = flags; - information->factory = empathy_contact_factory_dup_singleton (); filename = empathy_file_lookup ("empathy-contact-widget.ui", "libempathy-gtk"); @@ -206,12 +233,25 @@ empathy_contact_widget_new (EmpathyContact *contact, contact_widget_details_setup (information); contact_widget_client_setup (information); - contact_widget_set_contact (information, contact); + if (contact != NULL) + contact_widget_set_contact (information, contact); + + else if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT || + information->flags & EMPATHY_CONTACT_WIDGET_EDIT_ID) + contact_widget_change_contact (information); return empathy_builder_unref_and_keep_widget (gui, information->vbox_contact_widget); } +/** + * empathy_contact_widget_get_contact: + * @widget: an #EmpathyContactWidget + * + * Get the #EmpathyContact related with the #EmpathyContactWidget @widget. + * + * Returns: the #EmpathyContact associated with @widget + */ EmpathyContact * empathy_contact_widget_get_contact (GtkWidget *widget) { @@ -226,6 +266,13 @@ empathy_contact_widget_get_contact (GtkWidget *widget) return information->contact; } +/** + * empathy_contact_widget_set_contact: + * @widget: an #EmpathyContactWidget + * @contact: a different #EmpathyContact + * + * Change the #EmpathyContact related with the #EmpathyContactWidget @widget. + */ void empathy_contact_widget_set_contact (GtkWidget *widget, EmpathyContact *contact) @@ -242,6 +289,15 @@ empathy_contact_widget_set_contact (GtkWidget *widget, contact_widget_set_contact (information, contact); } +/** + * empathy_contact_widget_set_account_filter: + * @widget: an #EmpathyContactWidget + * @filter: a #EmpathyAccountChooserFilterFunc + * @user_data: user data to pass to @filter, or %NULL + * + * Set a filter on the #EmpathyAccountChooser included in the + * #EmpathyContactWidget. + */ void empathy_contact_widget_set_account_filter ( GtkWidget *widget, @@ -272,10 +328,6 @@ contact_widget_destroy_cb (GtkWidget *widget, { g_source_remove (information->widget_id_timeout); } - if (information->factory) - { - g_object_unref (information->factory); - } if (information->manager) { g_object_unref (information->manager); @@ -299,7 +351,9 @@ contact_widget_remove_contact (EmpathyContactWidget *information) contact_widget_groups_notify_cb, information); g_object_unref (information->contact); + g_object_unref (information->factory); information->contact = NULL; + information->factory = NULL; } } @@ -312,7 +366,13 @@ contact_widget_set_contact (EmpathyContactWidget *information, contact_widget_remove_contact (information); if (contact) + { + TpConnection *connection; + + connection = empathy_contact_get_connection (contact); information->contact = g_object_ref (contact); + information->factory = empathy_tp_contact_factory_dup_singleton (connection); + } /* Update information for widgets */ contact_widget_contact_update (information); @@ -491,10 +551,10 @@ static void update_avatar_chooser_account_cb (EmpathyAccountChooser *account_chooser, EmpathyAvatarChooser *avatar_chooser) { - McAccount *account; + TpConnection *connection; - account = empathy_account_chooser_get_account (account_chooser); - g_object_set (avatar_chooser, "account", account, NULL); + connection = empathy_account_chooser_get_connection (account_chooser); + g_object_set (avatar_chooser, "connection", connection, NULL); } static void @@ -505,8 +565,8 @@ contact_widget_contact_setup (EmpathyContactWidget *information) { information->widget_account = empathy_account_chooser_new (); - g_signal_connect (information->widget_account, "changed", - G_CALLBACK (contact_widget_account_changed_cb), + g_signal_connect_swapped (information->widget_account, "changed", + G_CALLBACK (contact_widget_change_contact), information); } else @@ -636,12 +696,12 @@ contact_widget_contact_update (EmpathyContactWidget *information) if (account) { g_signal_handlers_block_by_func (information->widget_account, - contact_widget_account_changed_cb, + contact_widget_change_contact, information); empathy_account_chooser_set_account ( EMPATHY_ACCOUNT_CHOOSER (information->widget_account), account); g_signal_handlers_unblock_by_func (information->widget_account, - contact_widget_account_changed_cb, information); + contact_widget_change_contact, information); } } else @@ -683,83 +743,71 @@ contact_widget_contact_update (EmpathyContactWidget *information) } static void -contact_widget_change_contact_cb (EmpathyContact *contact, - const GError *error, - gpointer information, - GObject *weak_object) +contact_widget_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *weak_object) { - if (error) - DEBUG ("Error: %s", error->message); - else - contact_widget_set_contact (information, contact); - g_object_unref (contact); + EmpathyContactWidget *information = user_data; + + if (error != NULL) + { + DEBUG ("Error: %s", error->message); + return; + } + + contact_widget_set_contact (information, contact); } static void contact_widget_change_contact (EmpathyContactWidget *information) { - EmpathyContact *contact; - McAccount *account; + EmpathyTpContactFactory *factory; + TpConnection *connection; - account = empathy_account_chooser_get_account ( + connection = empathy_account_chooser_get_connection ( EMPATHY_ACCOUNT_CHOOSER (information->widget_account)); - if (!account) + if (!connection) return; + factory = empathy_tp_contact_factory_dup_singleton (connection); if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_ID) { const gchar *id; id = gtk_entry_get_text (GTK_ENTRY (information->widget_id)); - if (EMP_STR_EMPTY (id)) - return; - - contact = empathy_contact_factory_get_from_id (information->factory, - account, id); + if (!EMP_STR_EMPTY (id)) + { + empathy_tp_contact_factory_get_from_id (factory, id, + contact_widget_got_contact_cb, information, NULL, + G_OBJECT (information->vbox_contact_widget)); + } } else { - contact = empathy_contact_factory_get_user (information->factory, - account); - } - - if (contact) - { - /* Give the contact ref to the callback */ - empathy_contact_call_when_ready (contact, - EMPATHY_CONTACT_READY_HANDLE | - EMPATHY_CONTACT_READY_ID, - contact_widget_change_contact_cb, - information, NULL, + empathy_tp_contact_factory_get_from_handle (factory, + tp_connection_get_self_handle (connection), + contact_widget_got_contact_cb, information, NULL, G_OBJECT (information->vbox_contact_widget)); } + + g_object_unref (factory); } static void contact_widget_avatar_changed_cb (EmpathyAvatarChooser *chooser, EmpathyContactWidget *information) { - if (information->contact && empathy_contact_is_user (information->contact)) - { - McAccount *account; - const gchar *data; - gsize size; - const gchar *mime_type; - - account = empathy_contact_get_account (information->contact); - empathy_avatar_chooser_get_image_data ( - EMPATHY_AVATAR_CHOOSER (information->widget_avatar), - &data, &size, &mime_type); - empathy_contact_factory_set_avatar (information->factory, account, - data, size, mime_type); - } -} - -static void -contact_widget_account_changed_cb (GtkComboBox *widget, - EmpathyContactWidget *information) -{ - contact_widget_change_contact (information); + const gchar *data; + gsize size; + const gchar *mime_type; + + empathy_avatar_chooser_get_image_data ( + EMPATHY_AVATAR_CHOOSER (information->widget_avatar), + &data, &size, &mime_type); + empathy_tp_contact_factory_set_avatar (information->factory, + data, size, mime_type); } static gboolean @@ -781,7 +829,7 @@ contact_widget_entry_alias_focus_event_cb (GtkEditable *editable, const gchar *alias; alias = gtk_entry_get_text (GTK_ENTRY (editable)); - empathy_contact_factory_set_alias (information->factory, + empathy_tp_contact_factory_set_alias (information->factory, information->contact, alias); } diff --git a/libempathy-gtk/empathy-contact-widget.h b/libempathy-gtk/empathy-contact-widget.h index 4ba75e17..0da5580a 100644 --- a/libempathy-gtk/empathy-contact-widget.h +++ b/libempathy-gtk/empathy-contact-widget.h @@ -29,6 +29,27 @@ G_BEGIN_DECLS +/** + * EmpathyContactWidgetFlags: + * @EMPATHY_CONTACT_WIDGET_EDIT_NONE: Don't show any widgets to edit any details + * of the contact. This should be the option for widgets that merely display + * information about a contact. + * @EMPATHY_CONTACT_WIDGET_EDIT_ALIAS: Show a #GtkEntry allowing changes to the + * contact's alias. + * @EMPATHY_CONTACT_WIDGET_EDIT_AVATAR: Show an #EmpathyAvatarChooser allowing + * changes to the contact's avatar. + * @EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT: Show an #EmpathyAccountChooser allowing + * changes to the contact's account. + * @EMPATHY_CONTACT_WIDGET_EDIT_ID: Show a #GtkEntry allowing changes to the + * contact's identifier. + * @EMPATHY_CONTACT_WIDGET_EDIT_GROUPS: Show a widget to change the groups the + * contact is in. + * @EMPATHY_CONTACT_WIDGET_FOR_TOOLTIP: Make widgets more designed for a tooltip. + * For example, make widgets not selectable. + * + * Flags used when creating an #EmpathyContactWidget to specify which features + * should be available. + */ typedef enum { EMPATHY_CONTACT_WIDGET_EDIT_NONE = 0, diff --git a/libempathy-gtk/empathy-irc-network-dialog.c b/libempathy-gtk/empathy-irc-network-dialog.c index 89ee5b28..8f7f47bd 100644 --- a/libempathy-gtk/empathy-irc-network-dialog.c +++ b/libempathy-gtk/empathy-irc-network-dialog.c @@ -572,6 +572,7 @@ empathy_irc_network_dialog_show (EmpathyIrcNetwork *network, gtk_window_set_modal (GTK_WINDOW (dialog->dialog), TRUE); irc_network_dialog_network_update_buttons (dialog); + gtk_widget_show_all (dialog->dialog); return dialog->dialog; } diff --git a/libempathy-gtk/empathy-log-window.c b/libempathy-gtk/empathy-log-window.c index 2cec1778..13d9bcbd 100644 --- a/libempathy-gtk/empathy-log-window.c +++ b/libempathy-gtk/empathy-log-window.c @@ -618,7 +618,7 @@ log_window_chats_populate (EmpathyLogWindow *window) GtkTreeIter iter; account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser_chats); - account = empathy_account_chooser_get_account (account_chooser); + account = empathy_account_chooser_dup_account (account_chooser); view = GTK_TREE_VIEW (window->treeview_chats); model = gtk_tree_view_get_model (view); diff --git a/libempathy-gtk/empathy-new-message-dialog.c b/libempathy-gtk/empathy-new-message-dialog.c index f6eb46a5..3e6e3f11 100644 --- a/libempathy-gtk/empathy-new-message-dialog.c +++ b/libempathy-gtk/empathy-new-message-dialog.c @@ -31,7 +31,7 @@ #include #include -#include +#include #include #include #include @@ -44,6 +44,16 @@ #include "empathy-new-message-dialog.h" #include "empathy-account-chooser.h" +/** + * SECTION:empathy-new-message-dialog + * @title: EmpathyNewMessageDialog + * @short_description: A dialog to show a new message + * @include: libempathy-gtk/empathy-new-message-dialog.h + * + * #EmpathyNewMessageDialog is a dialog which allows a text chat or + * call to be started with any contact on any enabled account. + */ + typedef struct { GtkWidget *dialog; GtkWidget *table_contact; @@ -65,48 +75,54 @@ new_message_dialog_account_changed_cb (GtkWidget *widget, EmpathyNewMessageDialog *dialog) { EmpathyAccountChooser *chooser; - McAccount *account; + TpConnection *connection; EmpathyTpContactList *contact_list; - GList *members, *l; + GList *members; GtkListStore *store; GtkEntryCompletion *completion; GtkTreeIter iter; gchar *tmpstr; - chooser = EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser); - account = empathy_account_chooser_get_account (chooser); - contact_list = empathy_contact_manager_get_list (dialog->contact_manager, - account); - members = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (contact_list)); + /* Remove completions */ completion = gtk_entry_get_completion (GTK_ENTRY (dialog->entry_id)); store = GTK_LIST_STORE (gtk_entry_completion_get_model (completion)); gtk_list_store_clear (store); - for (l = members; l; l = l->next) { - EmpathyContact *contact = l->data; + /* Get members of the new account */ + chooser = EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser); + connection = empathy_account_chooser_get_connection (chooser); + if (!connection) { + return; + } + contact_list = empathy_contact_manager_get_list (dialog->contact_manager, + connection); + members = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (contact_list)); + + /* Add members to the completion */ + while (members) { + EmpathyContact *contact = members->data; - if (!empathy_contact_is_online (contact)) { - continue; - } + if (empathy_contact_is_online (contact)) { + DEBUG ("Adding contact ID %s, Name %s", + empathy_contact_get_id (contact), + empathy_contact_get_name (contact)); - DEBUG ("Adding contact ID %s, Name %s", - empathy_contact_get_id (contact), - empathy_contact_get_name (contact)); + tmpstr = g_strdup_printf ("%s (%s)", + empathy_contact_get_name (contact), + empathy_contact_get_id (contact)); - tmpstr = g_strdup_printf ("%s (%s)", - empathy_contact_get_name (contact), - empathy_contact_get_id (contact)); + gtk_list_store_insert_with_values (store, &iter, -1, + COMPLETION_COL_TEXT, tmpstr, + COMPLETION_COL_ID, empathy_contact_get_id (contact), + COMPLETION_COL_NAME, empathy_contact_get_name (contact), + -1); - gtk_list_store_insert_with_values (store, &iter, -1, - COMPLETION_COL_TEXT, tmpstr, - COMPLETION_COL_ID, empathy_contact_get_id (contact), - COMPLETION_COL_NAME, empathy_contact_get_name (contact), - -1); + g_free (tmpstr); + } - g_free (tmpstr); + g_object_unref (contact); + members = g_list_delete_link (members, members); } - - g_object_unref (account); } static gboolean @@ -165,42 +181,52 @@ new_message_dialog_match_func (GtkEntryCompletion *completion, return FALSE; } +static void +new_message_dialog_call_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + EmpathyCallFactory *call_factory; + + if (error != NULL) { + DEBUG ("Error: %s", error->message); + return; + } + + call_factory = empathy_call_factory_get(); + empathy_call_factory_new_call (call_factory, contact); +} + static void new_message_dialog_response_cb (GtkWidget *widget, gint response, EmpathyNewMessageDialog *dialog) { - McAccount *account; + TpConnection *connection; const gchar *id; - account = empathy_account_chooser_get_account (EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser)); + connection = empathy_account_chooser_get_connection ( + EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser)); id = gtk_entry_get_text (GTK_ENTRY (dialog->entry_id)); - if (!account || EMP_STR_EMPTY (id)) { - if (account) { - g_object_unref (account); - } + if (!connection || EMP_STR_EMPTY (id)) { gtk_widget_destroy (widget); return; } if (response == 1) { - EmpathyContactFactory *factory; - EmpathyContact *contact; - EmpathyCallFactory *call_factory; - - factory = empathy_contact_factory_dup_singleton (); - contact = empathy_contact_factory_get_from_id (factory, account, id); + EmpathyTpContactFactory *factory; - call_factory = empathy_call_factory_get(); - empathy_call_factory_new_call (call_factory, contact); - - g_object_unref (contact); + factory = empathy_tp_contact_factory_dup_singleton (connection); + empathy_tp_contact_factory_get_from_id (factory, id, + new_message_dialog_call_got_contact_cb, + NULL, NULL, NULL); g_object_unref (factory); } else if (response == 2) { - empathy_dispatcher_chat_with_contact_id (account, id, NULL, NULL); + empathy_dispatcher_chat_with_contact_id (connection, id, NULL, NULL); } - g_object_unref (account); gtk_widget_destroy (widget); } @@ -226,6 +252,14 @@ new_message_dialog_destroy_cb (GtkWidget *widget, g_free (dialog); } +/** + * empathy_new_message_dialog_show: + * @parent: parent #GtkWindow of the dialog + * + * Create a new #EmpathyNewMessageDialog and show it. + * + * Return value: the new #EmpathyNewMessageDialog + */ GtkWidget * empathy_new_message_dialog_show (GtkWindow *parent) { diff --git a/libempathy-gtk/empathy-presence-chooser.c b/libempathy-gtk/empathy-presence-chooser.c index 8e9574bc..f4a325b5 100644 --- a/libempathy-gtk/empathy-presence-chooser.c +++ b/libempathy-gtk/empathy-presence-chooser.c @@ -46,6 +46,24 @@ #include "empathy-ui-utils.h" #include "empathy-images.h" #include "empathy-presence-chooser.h" +#include "empathy-status-preset-dialog.h" + +/** + * SECTION:empathy-presence-chooser + * @title:EmpathyPresenceChooser + * @short_description: A widget used to change presence + * @include: libempathy-gtk/empathy-presence-chooser.h + * + * #EmpathyPresenceChooser is a widget which extends #GtkComboBoxEntry + * to change presence. + */ + +/** + * EmpathyAccountChooser: + * @parent: parent object + * + * Widget which extends #GtkComboBoxEntry to change presence. + */ /* Flashing delay for icons (milliseconds). */ #define FLASH_TIMEOUT 500 @@ -95,16 +113,6 @@ typedef struct { guint flash_timeout_id; } EmpathyPresenceChooserPriv; -typedef struct { - GtkWidget *dialog; - GtkWidget *checkbutton_save; - GtkWidget *comboboxentry_message; - GtkWidget *entry_message; - GtkWidget *combobox_status; - GtkTreeModel *model_status; -} CustomMessageDialog; - -static CustomMessageDialog *message_dialog = NULL; /* States to be listed in the menu. * Each state has a boolean telling if it can have custom message */ static guint states[] = {MC_PRESENCE_AVAILABLE, TRUE, @@ -130,7 +138,6 @@ static void presence_chooser_set_state (McPresence const gchar *status); static void presence_chooser_custom_activate_cb (GtkWidget *item, gpointer user_data); -static void presence_chooser_dialog_show (GtkWindow *parent); G_DEFINE_TYPE (EmpathyPresenceChooser, empathy_presence_chooser, GTK_TYPE_COMBO_BOX_ENTRY); @@ -180,7 +187,8 @@ presence_chooser_create_model (EmpathyPresenceChooser *self) if (states[i+1]) { /* Set custom messages if wanted */ - list = empathy_status_presets_get (states[i], 5); + list = empathy_status_presets_get (states[i], -1); + list = g_list_sort (list, (GCompareFunc) g_utf8_collate); for (l = list; l; l = l->next) { gtk_list_store_insert_with_values (store, NULL, -1, @@ -576,7 +584,7 @@ presence_chooser_changed_cb (GtkComboBox *self, gpointer user_data) } if (type == ENTRY_TYPE_EDIT_CUSTOM) { - GtkWidget *window; + GtkWidget *window, *dialog; presence_chooser_reset_status (EMPATHY_PRESENCE_CHOOSER (self)); @@ -586,7 +594,9 @@ presence_chooser_changed_cb (GtkComboBox *self, gpointer user_data) window = NULL; } - presence_chooser_dialog_show (GTK_WINDOW (window)); + dialog = empathy_status_preset_dialog_new (GTK_WINDOW (window)); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); } else if (type == ENTRY_TYPE_CUSTOM) { gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry), @@ -789,6 +799,13 @@ presence_chooser_finalize (GObject *object) G_OBJECT_CLASS (empathy_presence_chooser_parent_class)->finalize (object); } +/** + * empathy_presence_chooser_new: + * + * Creates a new #EmpathyPresenceChooser widget. + * + * Return value: A new #EmpathyPresenceChooser widget + */ GtkWidget * empathy_presence_chooser_new (void) { @@ -946,6 +963,13 @@ presence_chooser_flash_stop (EmpathyPresenceChooser *chooser, empathy_icon_name_for_presence (state)); } +/** + * empathy_presence_chooser_create_menu: + * + * Creates a new #GtkMenu allowing users to change their presence from a menu. + * + * Return value: a new #GtkMenu for changing presence in a menu. + */ GtkWidget * empathy_presence_chooser_create_menu (void) { @@ -1058,220 +1082,9 @@ static void presence_chooser_custom_activate_cb (GtkWidget *item, gpointer user_data) { - presence_chooser_dialog_show (NULL); -} - -static McPresence -presence_chooser_dialog_get_selected (CustomMessageDialog *dialog) -{ - GtkTreeModel *model; - GtkTreeIter iter; - McPresence presence = LAST_MC_PRESENCE; + GtkWidget *dialog; - model = gtk_combo_box_get_model (GTK_COMBO_BOX (dialog->combobox_status)); - if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (dialog->combobox_status), &iter)) { - gtk_tree_model_get (model, &iter, - COL_PRESENCE, &presence, - -1); - } - - return presence; + dialog = empathy_status_preset_dialog_new (NULL); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); } - -static void -presence_chooser_dialog_status_changed_cb (GtkWidget *widget, - CustomMessageDialog *dialog) -{ - GtkListStore *store; - GtkTreeIter iter; - McPresence presence = LAST_MC_PRESENCE; - GList *messages, *l; - - presence = presence_chooser_dialog_get_selected (dialog); - - store = gtk_list_store_new (1, G_TYPE_STRING); - messages = empathy_status_presets_get (presence, -1); - for (l = messages; l; l = l->next) { - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, 0, l->data, -1); - } - - gtk_entry_set_text (GTK_ENTRY (dialog->entry_message), - messages ? messages->data : ""); - - g_list_free (messages); - - gtk_combo_box_set_model (GTK_COMBO_BOX (dialog->comboboxentry_message), - GTK_TREE_MODEL (store)); - - g_object_unref (store); -} - -static void -presence_chooser_dialog_message_changed_cb (GtkWidget *widget, - CustomMessageDialog *dialog) -{ - McPresence presence; - GList *messages, *l; - const gchar *text; - gboolean found = FALSE; - - presence = presence_chooser_dialog_get_selected (dialog); - text = gtk_entry_get_text (GTK_ENTRY (dialog->entry_message)); - - messages = empathy_status_presets_get (presence, -1); - for (l = messages; l; l = l->next) { - if (!tp_strdiff (text, l->data)) { - found = TRUE; - break; - } - } - g_list_free (messages); - - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->checkbutton_save), - found); -} - -static void -presence_chooser_dialog_save_toggled_cb (GtkWidget *widget, - CustomMessageDialog *dialog) -{ - gboolean active; - McPresence state; - const gchar *text; - - active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->checkbutton_save)); - state = presence_chooser_dialog_get_selected (dialog); - text = gtk_entry_get_text (GTK_ENTRY (dialog->entry_message)); - - if (active) { - empathy_status_presets_set_last (state, text); - } else { - empathy_status_presets_remove (state, text); - } -} - -static void -presence_chooser_dialog_setup (CustomMessageDialog *dialog) -{ - GtkListStore *store; - GtkCellRenderer *renderer; - GtkTreeIter iter; - guint i; - - store = gtk_list_store_new (COL_COUNT, - G_TYPE_STRING, /* Icon name */ - G_TYPE_STRING, /* Label */ - MC_TYPE_PRESENCE); /* Presence */ - gtk_combo_box_set_model (GTK_COMBO_BOX (dialog->combobox_status), - GTK_TREE_MODEL (store)); - - renderer = gtk_cell_renderer_pixbuf_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (dialog->combobox_status), renderer, FALSE); - gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (dialog->combobox_status), renderer, - "icon-name", COL_ICON, - NULL); - g_object_set (renderer, "stock-size", GTK_ICON_SIZE_BUTTON, NULL); - - renderer = gtk_cell_renderer_text_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (dialog->combobox_status), renderer, TRUE); - gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (dialog->combobox_status), renderer, - "text", COL_LABEL, - NULL); - - for (i = 0; i < G_N_ELEMENTS (states); i += 2) { - if (!states[i+1]) { - continue; - } - - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - COL_ICON, empathy_icon_name_for_presence (states[i]), - COL_LABEL, empathy_presence_get_default_message (states[i]), - COL_PRESENCE, states[i], - -1); - } - - gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->combobox_status), 0); -} - -static void -presence_chooser_dialog_response_cb (GtkWidget *widget, - gint response, - CustomMessageDialog *dialog) -{ - if (response == GTK_RESPONSE_APPLY) { - McPresence state; - const gchar *text; - - state = presence_chooser_dialog_get_selected (dialog); - text = gtk_entry_get_text (GTK_ENTRY (dialog->entry_message)); - - presence_chooser_set_state (state, text); - } - - gtk_widget_destroy (widget); -} - -static void -presence_chooser_dialog_destroy_cb (GtkWidget *widget, - CustomMessageDialog *dialog) -{ - - g_free (dialog); - message_dialog = NULL; -} - -static void -presence_chooser_dialog_show (GtkWindow *parent) -{ - GtkBuilder *gui; - gchar *filename; - - if (message_dialog) { - gtk_window_present (GTK_WINDOW (message_dialog->dialog)); - return; - } - - message_dialog = g_new0 (CustomMessageDialog, 1); - - filename = empathy_file_lookup ("empathy-presence-chooser.ui", - "libempathy-gtk"); - gui = empathy_builder_get_file (filename, - "custom_message_dialog", &message_dialog->dialog, - "checkbutton_save", &message_dialog->checkbutton_save, - "comboboxentry_message", &message_dialog->comboboxentry_message, - "combobox_status", &message_dialog->combobox_status, - NULL); - g_free (filename); - - empathy_builder_connect (gui, message_dialog, - "custom_message_dialog", "destroy", presence_chooser_dialog_destroy_cb, - "custom_message_dialog", "response", presence_chooser_dialog_response_cb, - "combobox_status", "changed", presence_chooser_dialog_status_changed_cb, - "checkbutton_save", "toggled", presence_chooser_dialog_save_toggled_cb, - NULL); - - g_object_unref (gui); - - /* Setup the message combobox */ - message_dialog->entry_message = GTK_BIN (message_dialog->comboboxentry_message)->child; - gtk_entry_set_activates_default (GTK_ENTRY (message_dialog->entry_message), TRUE); - gtk_entry_set_width_chars (GTK_ENTRY (message_dialog->entry_message), 25); - g_signal_connect (message_dialog->entry_message, "changed", - G_CALLBACK (presence_chooser_dialog_message_changed_cb), - message_dialog); - - presence_chooser_dialog_setup (message_dialog); - - gtk_combo_box_entry_set_text_column (GTK_COMBO_BOX_ENTRY (message_dialog->comboboxentry_message), 0); - - if (parent) { - gtk_window_set_transient_for ( - GTK_WINDOW (message_dialog->dialog), - parent); - } - - gtk_widget_show_all (message_dialog->dialog); -} - diff --git a/libempathy-gtk/empathy-presence-chooser.h b/libempathy-gtk/empathy-presence-chooser.h index 138e1dc7..dab95f55 100644 --- a/libempathy-gtk/empathy-presence-chooser.h +++ b/libempathy-gtk/empathy-presence-chooser.h @@ -43,6 +43,8 @@ typedef struct _EmpathyPresenceChooserClass EmpathyPresenceChooserClass; struct _EmpathyPresenceChooser { GtkComboBoxEntry parent; + + /**/ gpointer priv; }; diff --git a/libempathy-gtk/empathy-presence-chooser.ui b/libempathy-gtk/empathy-presence-chooser.ui deleted file mode 100644 index 6e0a155d..00000000 --- a/libempathy-gtk/empathy-presence-chooser.ui +++ /dev/null @@ -1,140 +0,0 @@ - - - - - - True - 5 - Custom message - False - dialog - False - - - True - - - True - 5 - 3 - 2 - 6 - 6 - - - True - - - 1 - 2 - GTK_FILL - GTK_FILL - - - - - True - - - 1 - 2 - 1 - 2 - GTK_FILL - GTK_FILL - - - - - Save message - True - True - False - True - True - - - 2 - 2 - 3 - - - - - - True - 0 - Message: - - - 1 - 2 - GTK_FILL - - - - - - True - 0 - Status: - - - GTK_FILL - - - - - - 1 - - - - - True - end - - - gtk-cancel - True - True - True - False - True - - - False - False - 0 - - - - - gtk-apply - True - True - True - False - True - - - False - False - 1 - - - - - False - end - 0 - - - - - - closebutton1 - button1 - - - diff --git a/libempathy-gtk/empathy-profile-chooser.c b/libempathy-gtk/empathy-profile-chooser.c index fd68dd8b..10eb3791 100644 --- a/libempathy-gtk/empathy-profile-chooser.c +++ b/libempathy-gtk/empathy-profile-chooser.c @@ -30,6 +30,16 @@ #include "empathy-profile-chooser.h" #include "empathy-ui-utils.h" +/** + * SECTION:empathy-profile-chooser + * @title: EmpathyProfileChooser + * @short_description: A widget used to choose from a list of profiles + * @include: libempathy-gtk/empathy-account-chooser.h + * + * #EmpathyProfileChooser is a widget which provides a chooser of available + * profiles. + */ + enum { COL_ICON, COL_LABEL, @@ -37,8 +47,17 @@ enum { COL_COUNT }; +/** + * empathy_profile_chooser_dup_selected: + * @widget: an #EmpathyProfileChooser + * + * Returns a new reference to the selected #McProfile in @widget. The returned + * #McProfile should be unrefed with g_object_unref() when finished with. + * + * Return value: a new reference to the selected #McProfile + */ McProfile* -empathy_profile_chooser_get_selected (GtkWidget *widget) +empathy_profile_chooser_dup_selected (GtkWidget *widget) { GtkTreeModel *model; GtkTreeIter iter; @@ -54,6 +73,14 @@ empathy_profile_chooser_get_selected (GtkWidget *widget) return profile; } +/** + * empathy_profile_chooser_n_profiles: + * @widget: an #EmpathyProfileChooser + * + * Returns the number of profiles in @widget. + * + * Return value: the number of profiles in @widget + */ gint empathy_profile_chooser_n_profiles (GtkWidget *widget) { @@ -115,6 +142,13 @@ profile_chooser_sort_func (GtkTreeModel *model, return cmp; } +/** + * empathy_profile_chooser_new: + * + * Creates a new #EmpathyProfileChooser widget. + * + * Return value: a new #EmpathyProfileChooser widget + */ GtkWidget * empathy_profile_chooser_new (void) { diff --git a/libempathy-gtk/empathy-profile-chooser.h b/libempathy-gtk/empathy-profile-chooser.h index 8cdc33d6..74c761cc 100644 --- a/libempathy-gtk/empathy-profile-chooser.h +++ b/libempathy-gtk/empathy-profile-chooser.h @@ -27,7 +27,7 @@ G_BEGIN_DECLS GtkWidget * empathy_profile_chooser_new (void); -McProfile * empathy_profile_chooser_get_selected (GtkWidget *widget); +McProfile * empathy_profile_chooser_dup_selected (GtkWidget *widget); gint empathy_profile_chooser_n_profiles (GtkWidget *widget); G_END_DECLS diff --git a/libempathy-gtk/empathy-spell-dialog.c b/libempathy-gtk/empathy-spell-dialog.c deleted file mode 100644 index 9ce80eeb..00000000 --- a/libempathy-gtk/empathy-spell-dialog.c +++ /dev/null @@ -1,264 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2004-2007 Imendio AB - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "config.h" - -#include - -#include -#include - -#include - -#include "empathy-chat.h" -#include "empathy-spell.h" -#include "empathy-spell-dialog.h" -#include "empathy-ui-utils.h" - -typedef struct { - GtkWidget *window; - GtkWidget *button_replace; - GtkWidget *label_word; - GtkWidget *treeview_words; - - EmpathyChat *chat; - - gchar *word; - GtkTextIter start; - GtkTextIter end; -} EmpathySpellDialog; - -enum { - COL_SPELL_WORD, - COL_SPELL_COUNT -}; - -static void spell_dialog_model_populate_columns (EmpathySpellDialog *dialog); -static void spell_dialog_model_populate_suggestions (EmpathySpellDialog *dialog); -static void spell_dialog_model_row_activated_cb (GtkTreeView *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column, - EmpathySpellDialog *dialog); -static void spell_dialog_model_selection_changed_cb (GtkTreeSelection *treeselection, - EmpathySpellDialog *dialog); -static void spell_dialog_model_setup (EmpathySpellDialog *dialog); -static void spell_dialog_response_cb (GtkWidget *widget, - gint response, - EmpathySpellDialog *dialog); -static void spell_dialog_destroy_cb (GtkWidget *widget, - EmpathySpellDialog *dialog); - -static void -spell_dialog_model_populate_columns (EmpathySpellDialog *dialog) -{ - GtkTreeModel *model; - GtkTreeViewColumn *column; - GtkCellRenderer *renderer; - guint col_offset; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview_words)); - - renderer = gtk_cell_renderer_text_new (); - col_offset = gtk_tree_view_insert_column_with_attributes ( - GTK_TREE_VIEW (dialog->treeview_words), - -1, _("Word"), - renderer, - "text", COL_SPELL_WORD, - NULL); - - g_object_set_data (G_OBJECT (renderer), - "column", GINT_TO_POINTER (COL_SPELL_WORD)); - - column = gtk_tree_view_get_column (GTK_TREE_VIEW (dialog->treeview_words), col_offset - 1); - gtk_tree_view_column_set_sort_column_id (column, COL_SPELL_WORD); - gtk_tree_view_column_set_resizable (column, FALSE); - gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); -} - -static void -spell_dialog_model_populate_suggestions (EmpathySpellDialog *dialog) -{ - GtkTreeModel *model; - GtkListStore *store; - GList *suggestions, *l; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview_words)); - store = GTK_LIST_STORE (model); - - suggestions = empathy_spell_get_suggestions (dialog->word); - for (l = suggestions; l; l=l->next) { - GtkTreeIter iter; - gchar *word; - - word = l->data; - - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - COL_SPELL_WORD, word, - -1); - } - - empathy_spell_free_suggestions (suggestions); -} - -static void -spell_dialog_model_row_activated_cb (GtkTreeView *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column, - EmpathySpellDialog *dialog) -{ - spell_dialog_response_cb (dialog->window, GTK_RESPONSE_OK, dialog); -} - -static void -spell_dialog_model_selection_changed_cb (GtkTreeSelection *treeselection, - EmpathySpellDialog *dialog) -{ - gint count; - - count = gtk_tree_selection_count_selected_rows (treeselection); - gtk_widget_set_sensitive (dialog->button_replace, (count == 1)); -} - -static void -spell_dialog_model_setup (EmpathySpellDialog *dialog) -{ - GtkTreeView *view; - GtkListStore *store; - GtkTreeSelection *selection; - - view = GTK_TREE_VIEW (dialog->treeview_words); - - g_signal_connect (view, "row-activated", - G_CALLBACK (spell_dialog_model_row_activated_cb), - dialog); - - store = gtk_list_store_new (COL_SPELL_COUNT, - G_TYPE_STRING); /* word */ - - gtk_tree_view_set_model (view, GTK_TREE_MODEL (store)); - - selection = gtk_tree_view_get_selection (view); - gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); - - g_signal_connect (selection, "changed", - G_CALLBACK (spell_dialog_model_selection_changed_cb), - dialog); - - spell_dialog_model_populate_columns (dialog); - spell_dialog_model_populate_suggestions (dialog); - - g_object_unref (store); -} - -static void -spell_dialog_destroy_cb (GtkWidget *widget, - EmpathySpellDialog *dialog) -{ - g_object_unref (dialog->chat); - g_free (dialog->word); - - g_free (dialog); -} - -static void -spell_dialog_response_cb (GtkWidget *widget, - gint response, - EmpathySpellDialog *dialog) -{ - if (response == GTK_RESPONSE_OK) { - GtkTreeView *view; - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - - gchar *new_word; - - view = GTK_TREE_VIEW (dialog->treeview_words); - selection = gtk_tree_view_get_selection (view); - - if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { - return; - } - - gtk_tree_model_get (model, &iter, COL_SPELL_WORD, &new_word, -1); - - empathy_chat_correct_word (dialog->chat, - &dialog->start, - &dialog->end, - new_word); - - g_free (new_word); - } - - gtk_widget_destroy (dialog->window); -} - -void -empathy_spell_dialog_show (EmpathyChat *chat, - GtkTextIter *start, - GtkTextIter *end, - const gchar *word) -{ - EmpathySpellDialog *dialog; - GtkBuilder *gui; - gchar *str; - gchar *filename; - - g_return_if_fail (chat != NULL); - g_return_if_fail (word != NULL); - - dialog = g_new0 (EmpathySpellDialog, 1); - - dialog->chat = g_object_ref (chat); - - dialog->word = g_strdup (word); - - dialog->start = *start; - dialog->end = *end; - - filename = empathy_file_lookup ("empathy-spell-dialog.ui", - "libempathy-gtk"); - gui = empathy_builder_get_file (filename, - "spell_dialog", &dialog->window, - "button_replace", &dialog->button_replace, - "label_word", &dialog->label_word, - "treeview_words", &dialog->treeview_words, - NULL); - g_free (filename); - - empathy_builder_connect (gui, dialog, - "spell_dialog", "response", spell_dialog_response_cb, - "spell_dialog", "destroy", spell_dialog_destroy_cb, - NULL); - - g_object_unref (gui); - - str = g_markup_printf_escaped ("%s:\n%s", - _("Suggestions for the word"), - word); - - gtk_label_set_markup (GTK_LABEL (dialog->label_word), str); - g_free (str); - - spell_dialog_model_setup (dialog); - - gtk_widget_show (dialog->window); -} diff --git a/libempathy-gtk/empathy-spell-dialog.h b/libempathy-gtk/empathy-spell-dialog.h deleted file mode 100644 index ce021881..00000000 --- a/libempathy-gtk/empathy-spell-dialog.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2004-2007 Imendio AB - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Martyn Russell - * Richard Hult - */ - -#ifndef __EMPATHY_SPELL_DIALOG_H__ -#define __EMPATHY_SPELL_DIALOG_H__ - -#include -#include "empathy-chat.h" - -G_BEGIN_DECLS - -void empathy_spell_dialog_show (EmpathyChat *chat, - GtkTextIter *start, - GtkTextIter *end, - const gchar *word); - -G_END_DECLS - -#endif /* __EMPATHY_SPELL_DIALOG_H__ */ diff --git a/libempathy-gtk/empathy-spell-dialog.ui b/libempathy-gtk/empathy-spell-dialog.ui deleted file mode 100644 index 382346c1..00000000 --- a/libempathy-gtk/empathy-spell-dialog.ui +++ /dev/null @@ -1,131 +0,0 @@ - - - - - 5 - Spell Checker - True - GTK_WIN_POS_CENTER_ON_PARENT - 275 - 225 - GDK_WINDOW_TYPE_HINT_DIALOG - False - - - True - 2 - - - True - 5 - 6 - - - True - 0 - Suggestions for the word: - True - True - - - False - False - - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - - - True - True - False - - - - - 1 - - - - - 1 - - - - - True - GTK_BUTTONBOX_END - - - True - True - True - gtk-cancel - True - - - - - True - False - True - True - - - True - 0 - 0 - - - True - 2 - - - True - gtk-convert - - - False - False - - - - - True - _Replace - True - - - False - False - 1 - - - - - - - - - 1 - - - - - False - GTK_PACK_END - - - - - - button_cancel - button_replace - - - diff --git a/libempathy-gtk/empathy-status-preset-dialog.c b/libempathy-gtk/empathy-status-preset-dialog.c new file mode 100644 index 00000000..734ac356 --- /dev/null +++ b/libempathy-gtk/empathy-status-preset-dialog.c @@ -0,0 +1,549 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * empathy-status-preset-dialog.c + * + * EmpathyStatusPresetDialog - a dialog for adding and removing preset status + * messages. + * + * Copyright (C) 2009 Collabora Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Davyd Madeley + */ +/** + * SECTION:empathy-status-preset-dialog + * @title: EmpathyStatusPresetDialog + * @short_description: a dialog for editing the saved status messages + * @include: libempathy-gtk/empathy-status-preset-dialog.h + * + * #EmpathyStatusPresetDialog is a dialog allowing the user to add/remove/edit + * their saved status messages. + */ + +#include "config.h" + +#include +#include + +#include + +#include +#include + +#define DEBUG_FLAG EMPATHY_DEBUG_OTHER +#include + +#include "empathy-ui-utils.h" +#include "empathy-status-preset-dialog.h" + +#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyStatusPresetDialog) + +G_DEFINE_TYPE (EmpathyStatusPresetDialog, empathy_status_preset_dialog, GTK_TYPE_DIALOG); + +static McPresence states[] = { + MC_PRESENCE_AVAILABLE, + MC_PRESENCE_DO_NOT_DISTURB, + MC_PRESENCE_AWAY +}; + +typedef struct _EmpathyStatusPresetDialogPriv EmpathyStatusPresetDialogPriv; +struct _EmpathyStatusPresetDialogPriv +{ + /* block status_preset_dialog_add_combo_changed() when > 0 */ + int block_add_combo_changed; + + GtkWidget *presets_treeview; + GtkWidget *add_combobox; + GtkWidget *add_button; + + GtkTreeIter selected_iter; + gboolean add_combo_changed; + char *saved_status; +}; + +enum +{ + PRESETS_STORE_STATE, + PRESETS_STORE_ICON_NAME, + PRESETS_STORE_STATUS, + PRESETS_STORE_N_COLS +}; + +enum +{ + ADD_COMBO_STATE, + ADD_COMBO_ICON_NAME, + ADD_COMBO_STATUS, + ADD_COMBO_DEFAULT_TEXT, + ADD_COMBO_N_COLS +}; + +static void +empathy_status_preset_dialog_finalize (GObject *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + + g_free (priv->saved_status); + + G_OBJECT_CLASS (empathy_status_preset_dialog_parent_class)->finalize (self); +} + +static void +empathy_status_preset_dialog_class_init (EmpathyStatusPresetDialogClass *class) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (class); + gobject_class->finalize = empathy_status_preset_dialog_finalize; + + g_type_class_add_private (gobject_class, + sizeof (EmpathyStatusPresetDialogPriv)); +} + +static void +status_preset_dialog_presets_update (EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkListStore *store; + int i; + + store = GTK_LIST_STORE (gtk_tree_view_get_model ( + GTK_TREE_VIEW (priv->presets_treeview))); + + gtk_list_store_clear (store); + + for (i = 0; i < G_N_ELEMENTS (states); i++) { + GList *presets, *l; + const char *icon_name; + + icon_name = empathy_icon_name_for_presence (states[i]); + presets = empathy_status_presets_get (states[i], -1); + presets = g_list_sort (presets, (GCompareFunc) g_utf8_collate); + + for (l = presets; l; l = l->next) { + char *preset = (char *) l->data; + + gtk_list_store_insert_with_values (store, + NULL, -1, + PRESETS_STORE_STATE, states[i], + PRESETS_STORE_ICON_NAME, icon_name, + PRESETS_STORE_STATUS, preset, + -1); + } + + g_list_free (presets); + } +} + +static void +status_preset_add_combo_reset (EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->add_combobox), + &priv->selected_iter); +} + +static void +status_preset_dialog_setup_add_combobox (EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkWidget *combobox = priv->add_combobox; + GtkListStore *store; + GtkCellRenderer *renderer; + int i; + + store = gtk_list_store_new (ADD_COMBO_N_COLS, + MC_TYPE_PRESENCE, /* ADD_COMBO_STATE */ + G_TYPE_STRING, /* ADD_COMBO_ICON_NAME */ + G_TYPE_STRING, /* ADD_COMBO_STATUS */ + G_TYPE_STRING); /* ADD_COMBO_DEFAULT_TEXT */ + + gtk_combo_box_set_model (GTK_COMBO_BOX (combobox), + GTK_TREE_MODEL (store)); + g_object_unref (store); + + gtk_combo_box_entry_set_text_column (GTK_COMBO_BOX_ENTRY (combobox), + ADD_COMBO_DEFAULT_TEXT); + + for (i = 0; i < G_N_ELEMENTS (states); i++) { + gtk_list_store_insert_with_values (store, NULL, -1, + ADD_COMBO_STATE, states[i], + ADD_COMBO_ICON_NAME, empathy_icon_name_for_presence (states[i]), + ADD_COMBO_STATUS, empathy_presence_get_default_message (states[i]), + ADD_COMBO_DEFAULT_TEXT, "", + -1); + } + + gtk_cell_layout_clear (GTK_CELL_LAYOUT (combobox)); + + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, FALSE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combobox), renderer, + "icon-name", ADD_COMBO_ICON_NAME); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, TRUE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combobox), renderer, + "text", ADD_COMBO_STATUS); + g_object_set (renderer, + "style", PANGO_STYLE_ITALIC, + "foreground", "Gray", /* FIXME - theme */ + NULL); + + gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), 0); +} + +static void +status_preset_dialog_status_edited (GtkCellRendererText *renderer, + char *path_str, + char *new_status, + EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkTreeModel *model; + GtkTreePath *path; + GtkTreeIter iter; + McPresence state; + char *old_status; + gboolean valid; + + if (strlen (new_status) == 0) { + /* status is empty, ignore */ + return; + } + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->presets_treeview)); + path = gtk_tree_path_new_from_string (path_str); + valid = gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_path_free (path); + + if (!valid) return; + + gtk_tree_model_get (model, &iter, + PRESETS_STORE_STATE, &state, + PRESETS_STORE_STATUS, &old_status, + -1); + + if (!strcmp (old_status, new_status)) { + /* statuses are the same */ + g_free (old_status); + return; + } + + DEBUG ("EDITED STATUS (%s) -> (%s)\n", old_status, new_status); + + empathy_status_presets_remove (state, old_status); + empathy_status_presets_set_last (state, new_status); + + g_free (old_status); + + status_preset_dialog_presets_update (self); +} + +static void +status_preset_dialog_setup_presets_treeview (EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkWidget *treeview = priv->presets_treeview; + GtkListStore *store; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + + store = gtk_list_store_new (PRESETS_STORE_N_COLS, + MC_TYPE_PRESENCE, /* PRESETS_STORE_STATE */ + G_TYPE_STRING, /* PRESETS_STORE_ICON_NAME */ + G_TYPE_STRING); /* PRESETS_STORE_STATUS */ + + gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), + GTK_TREE_MODEL (store)); + g_object_unref (store); + + status_preset_dialog_presets_update (self); + + column = gtk_tree_view_column_new (); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (column, renderer, FALSE); + gtk_tree_view_column_add_attribute (column, renderer, + "icon-name", PRESETS_STORE_ICON_NAME); + + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_add_attribute (column, renderer, + "text", PRESETS_STORE_STATUS); + g_object_set (renderer, + "editable", TRUE, + NULL); + g_signal_connect (renderer, "edited", + G_CALLBACK (status_preset_dialog_status_edited), self); +} + +static void +status_preset_dialog_preset_selection_changed (GtkTreeSelection *selection, + GtkWidget *remove_button) +{ + /* update the sensitivity of the Remove button */ + gtk_widget_set_sensitive (remove_button, + gtk_tree_selection_get_selected (selection, NULL, NULL)); +} + +static void +status_preset_dialog_preset_remove (GtkButton *button, + EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + McPresence state; + char *status; + + selection = gtk_tree_view_get_selection ( + GTK_TREE_VIEW (priv->presets_treeview)); + + g_return_if_fail (gtk_tree_selection_get_selected (selection, + &model, &iter)); + + gtk_tree_model_get (model, &iter, + PRESETS_STORE_STATE, &state, + PRESETS_STORE_STATUS, &status, + -1); + + DEBUG ("REMOVE PRESET (%i, %s)\n", state, status); + empathy_status_presets_remove (state, status); + + g_free (status); + + status_preset_dialog_presets_update (self); +} + +static void +status_preset_dialog_set_add_combo_changed (EmpathyStatusPresetDialog *self, + gboolean state, + gboolean reset_text) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkWidget *entry; + + entry = gtk_bin_get_child (GTK_BIN (priv->add_combobox)); + + priv->add_combo_changed = state; + gtk_widget_set_sensitive (priv->add_button, state); + + if (state) { + gtk_widget_modify_text (entry, GTK_STATE_NORMAL, NULL); + } else { + GdkColor colour; + + gdk_color_parse ("Gray", &colour); /* FIXME - theme */ + gtk_widget_modify_text (entry, GTK_STATE_NORMAL, &colour); + + if (reset_text) { + priv->block_add_combo_changed++; + gtk_entry_set_text (GTK_ENTRY (entry), + _("Enter Custom Message")); + priv->block_add_combo_changed--; + } + } +} + +static void +status_preset_dialog_add_combo_changed (GtkComboBox *combo, + EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkWidget *entry; + GtkTreeModel *model; + GtkTreeIter iter; + + if (priv->block_add_combo_changed) return; + + model = gtk_combo_box_get_model (combo); + entry = gtk_bin_get_child (GTK_BIN (combo)); + + if (gtk_combo_box_get_active_iter (combo, &iter)) { + char *icon_name; + + priv->selected_iter = iter; + gtk_tree_model_get (model, &iter, + PRESETS_STORE_ICON_NAME, &icon_name, + -1); + + gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry), + GTK_ENTRY_ICON_PRIMARY, + icon_name); + + g_free (icon_name); + + status_preset_dialog_set_add_combo_changed (self, FALSE, TRUE); + if (priv->saved_status && strlen (priv->saved_status) > 0) { + gtk_entry_set_text (GTK_ENTRY (entry), + priv->saved_status); + } + } else { + g_free (priv->saved_status); + priv->saved_status = g_strdup ( + gtk_entry_get_text (GTK_ENTRY (entry))); + + status_preset_dialog_set_add_combo_changed (self, + strlen (priv->saved_status) > 0, FALSE); + } +} + +static void +status_preset_dialog_add_preset (GtkWidget *widget, + EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkTreeModel *model; + GtkWidget *entry; + McPresence state; + const char *status; + + g_return_if_fail (priv->add_combo_changed); + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (priv->add_combobox)); + entry = gtk_bin_get_child (GTK_BIN (priv->add_combobox)); + + status = gtk_entry_get_text (GTK_ENTRY (entry)); + gtk_tree_model_get (model, &priv->selected_iter, + PRESETS_STORE_STATE, &state, + -1); + + DEBUG ("ADD PRESET (%i, %s)\n", state, status); + empathy_status_presets_set_last (state, status); + + status_preset_dialog_presets_update (self); + status_preset_add_combo_reset (self); +} + +static gboolean +status_preset_dialog_add_combo_press_event (GtkWidget *widget, + GdkEventButton *event, + EmpathyStatusPresetDialog *self) +{ + if (!GTK_WIDGET_HAS_FOCUS (widget)) { + /* if the widget isn't focused, focus it and select the text */ + gtk_widget_grab_focus (widget); + gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1); + + return TRUE; + } + + return FALSE; +} + +static gboolean +status_preset_dialog_add_combo_focus_out (GtkWidget *widget, + GdkEventFocus *event, + EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + const char *status; + + gtk_editable_set_position (GTK_EDITABLE (widget), 0); + + status = gtk_entry_get_text (GTK_ENTRY (widget)); + status_preset_dialog_set_add_combo_changed (self, + priv->add_combo_changed && strlen (status) > 0, + TRUE); + + return FALSE; +} + +static void +empathy_status_preset_dialog_init (EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = self->priv = + G_TYPE_INSTANCE_GET_PRIVATE (self, + EMPATHY_TYPE_STATUS_PRESET_DIALOG, + EmpathyStatusPresetDialogPriv); + GtkBuilder *gui; + GtkWidget *toplevel_vbox, *remove_button, *entry; + char *filename; + + gtk_window_set_title (GTK_WINDOW (self), + _("Edit Custom Messages")); + gtk_dialog_set_has_separator (GTK_DIALOG (self), FALSE); + gtk_dialog_add_button (GTK_DIALOG (self), + GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE); + + filename = empathy_file_lookup ("empathy-status-preset-dialog.ui", + "libempathy-gtk"); + gui = empathy_builder_get_file (filename, + "toplevel-vbox", &toplevel_vbox, + "presets-treeview", &priv->presets_treeview, + "remove-button", &remove_button, + "add-combobox", &priv->add_combobox, + "add-button", &priv->add_button, + NULL); + g_free (filename); + + g_signal_connect (gtk_tree_view_get_selection ( + GTK_TREE_VIEW (priv->presets_treeview)), + "changed", + G_CALLBACK (status_preset_dialog_preset_selection_changed), + remove_button); + + entry = gtk_bin_get_child (GTK_BIN (priv->add_combobox)); + g_signal_connect (entry, "activate", + G_CALLBACK (status_preset_dialog_add_preset), self); + g_signal_connect (entry, "button-press-event", + G_CALLBACK (status_preset_dialog_add_combo_press_event), + self); + g_signal_connect (entry, "focus-out-event", + G_CALLBACK (status_preset_dialog_add_combo_focus_out), + self); + + empathy_builder_connect (gui, self, + "remove-button", "clicked", status_preset_dialog_preset_remove, + "add-combobox", "changed", status_preset_dialog_add_combo_changed, + "add-button", "clicked", status_preset_dialog_add_preset, + NULL); + + status_preset_dialog_setup_presets_treeview (self); + status_preset_dialog_setup_add_combobox (self); + + gtk_box_pack_start(GTK_BOX (GTK_DIALOG (self)->vbox), toplevel_vbox, + TRUE, TRUE, 0); + + g_object_unref (gui); +} + +/** + * empathy_status_preset_dialog_new: + * @parent: the parent window of this dialog (or NULL) + * + * Creates a new #EmpathyStatusPresetDialog that allows the user to + * add/remove/edit their saved status messages. + * + * Returns: the newly constructed dialog. + */ +GtkWidget * +empathy_status_preset_dialog_new (GtkWindow *parent) +{ + GtkWidget *self = g_object_new (EMPATHY_TYPE_STATUS_PRESET_DIALOG, + NULL); + + if (parent) { + gtk_window_set_transient_for (GTK_WINDOW (self), parent); + } + + return self; +} diff --git a/libempathy-gtk/empathy-status-preset-dialog.h b/libempathy-gtk/empathy-status-preset-dialog.h new file mode 100644 index 00000000..e53c3d8a --- /dev/null +++ b/libempathy-gtk/empathy-status-preset-dialog.h @@ -0,0 +1,63 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * empathy-status-preset-dialog.c + * + * EmpathyStatusPresetDialog - a dialog for adding and removing preset status + * messages. + * + * Copyright (C) 2009 Collabora Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Davyd Madeley + */ + +#ifndef __EMPATHY_STATUS_PRESET_DIALOG_H__ +#define __EMPATHY_STATUS_PRESET_DIALOG_H__ + +#include + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_STATUS_PRESET_DIALOG (empathy_status_preset_dialog_get_type ()) +#define EMPATHY_STATUS_PRESET_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EMPATHY_TYPE_STATUS_PRESET_DIALOG, EmpathyStatusPresetDialog)) +#define EMPATHY_STATUS_PRESET_DIALOG_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), EMPATHY_TYPE_STATUS_PRESET_DIALOG, EmpathyStatusPresetDialogClass)) +#define EMPATHY_IS_STATUS_PRESET_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EMPATHY_TYPE_STATUS_PRESET_DIALOG)) +#define EMPATHY_IS_STATUS_PRESET_DIALOG_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), EMPATHY_TYPE_STATUS_PRESET_DIALOG)) +#define EMPATHY_STATUS_PRESET_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EMPATHY_TYPE_STATUS_PRESET_DIALOG, EmpathyStatusPresetDialogClass)) + +typedef struct _EmpathyStatusPresetDialog EmpathyStatusPresetDialog; +typedef struct _EmpathyStatusPresetDialogClass EmpathyStatusPresetDialogClass; + +struct _EmpathyStatusPresetDialog +{ + GtkDialog parent; + + /*< private >*/ + gpointer priv; +}; + +struct _EmpathyStatusPresetDialogClass +{ + GtkDialogClass parent_class; +}; + +GType empathy_status_preset_dialog_get_type (void); +GtkWidget *empathy_status_preset_dialog_new (GtkWindow *parent); + +G_END_DECLS + +#endif diff --git a/libempathy-gtk/empathy-status-preset-dialog.ui b/libempathy-gtk/empathy-status-preset-dialog.ui new file mode 100644 index 00000000..ead8ab85 --- /dev/null +++ b/libempathy-gtk/empathy-status-preset-dialog.ui @@ -0,0 +1,116 @@ + + + + + + True + 6 + vertical + 6 + + + True + 0 + Saved Presets + add-combobox + + + + + + False + 0 + + + + + True + True + never + etched-in + + + True + True + False + + + + + 1 + + + + + True + end + + + gtk-remove + True + False + True + True + True + + + False + False + 0 + + + + + False + 2 + + + + + True + 0 + Add _New Preset + True + add-combobox + + + + + + False + 3 + + + + + True + 3 + + + True + + + 0 + + + + + gtk-add + True + False + True + True + True + + + 1 + + + + + False + 4 + + + + diff --git a/libempathy-gtk/empathy-theme-boxes.c b/libempathy-gtk/empathy-theme-boxes.c index 0561ecac..5b435f1d 100644 --- a/libempathy-gtk/empathy-theme-boxes.c +++ b/libempathy-gtk/empathy-theme-boxes.c @@ -208,9 +208,9 @@ theme_boxes_maybe_append_header (EmpathyThemeBoxes *theme, DEBUG ("Maybe add fancy header"); /* Only insert a header if the previously inserted block is not the same - * as this one. This catches all the different cases: + * as this one. */ - if (last_contact && empathy_contact_equal (last_contact, contact)) { + if (last_contact == contact) { return; } diff --git a/libempathy-gtk/empathy-ui-utils.c b/libempathy-gtk/empathy-ui-utils.c index aa349289..9a249e65 100644 --- a/libempathy-gtk/empathy-ui-utils.c +++ b/libempathy-gtk/empathy-ui-utils.c @@ -102,7 +102,7 @@ builder_get_file_valist (const gchar *filename, gui = gtk_builder_new (); if (!gtk_builder_add_from_file (gui, filename, &error)) { - DEBUG ("Error: %s", error->message); + g_critical ("GtkBuilder Error: %s", error->message); g_clear_error (&error); g_object_unref (gui); return NULL; diff --git a/libempathy/Makefile.am b/libempathy/Makefile.am index f82f4cc0..ba1f6f8c 100644 --- a/libempathy/Makefile.am +++ b/libempathy/Makefile.am @@ -21,10 +21,9 @@ libempathy_la_SOURCES = \ empathy-account-manager.c \ empathy-chatroom.c \ empathy-chatroom-manager.c \ - empathy-call-factory.c \ - empathy-call-handler.c \ + empathy-call-factory.c \ + empathy-call-handler.c \ empathy-contact.c \ - empathy-contact-factory.c \ empathy-contact-groups.c \ empathy-contact-list.c \ empathy-contact-manager.c \ @@ -47,7 +46,6 @@ libempathy_la_SOURCES = \ empathy-tp-contact-factory.c \ empathy-tp-contact-list.c \ empathy-tp-file.c \ - empathy-tp-group.c \ empathy-tp-roomlist.c \ empathy-tp-tube.c \ empathy-tube-handler.c \ @@ -72,7 +70,6 @@ libempathy_headers = \ empathy-call-factory.h \ empathy-call-handler.h \ empathy-contact.h \ - empathy-contact-factory.h \ empathy-contact-groups.h \ empathy-contact-list.h \ empathy-contact-manager.h \ @@ -95,7 +92,6 @@ libempathy_headers = \ empathy-tp-contact-factory.h \ empathy-tp-contact-list.h \ empathy-tp-file.h \ - empathy-tp-group.h \ empathy-tp-roomlist.h \ empathy-tp-tube.h \ empathy-tube-handler.h \ diff --git a/libempathy/empathy-account-manager.c b/libempathy/empathy-account-manager.c index 5962a867..b8454317 100644 --- a/libempathy/empathy-account-manager.c +++ b/libempathy/empathy-account-manager.c @@ -26,19 +26,24 @@ #include "empathy-marshal.h" #include "empathy-utils.h" +#define DEBUG_FLAG EMPATHY_DEBUG_ACCOUNT +#include + #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccountManager) typedef struct { McAccountMonitor *monitor; MissionControl *mc; - GHashTable *accounts; + GHashTable *accounts; /* McAccount -> AccountData */ + GHashTable *connections; /* TpConnection -> McAccount */ int connected; int connecting; gboolean dispose_run; } EmpathyAccountManagerPriv; typedef struct { + TpConnection *connection; McPresence presence; TpConnectionStatus status; gboolean is_enabled; @@ -54,6 +59,7 @@ enum { ACCOUNT_CHANGED, ACCOUNT_CONNECTION_CHANGED, ACCOUNT_PRESENCE_CHANGED, + NEW_CONNECTION, LAST_SIGNAL }; @@ -112,10 +118,74 @@ account_data_free (AccountData *data) g_source_remove (data->source_id); data->source_id = 0; } + if (data->connection != NULL) + { + g_object_unref (data->connection); + data->connection = NULL; + } g_slice_free (AccountData, data); } +static void +connection_invalidated_cb (TpProxy *connection, + guint domain, + gint code, + gchar *message, + EmpathyAccountManager *manager) +{ + EmpathyAccountManagerPriv *priv = GET_PRIV (manager); + McAccount *account; + AccountData *data; + + DEBUG ("Message: %s", message); + + account = g_hash_table_lookup (priv->connections, connection); + g_assert (account != NULL); + + data = g_hash_table_lookup (priv->accounts, account); + g_assert (data != NULL); + + g_object_unref (data->connection); + data->connection = NULL; + + g_hash_table_remove (priv->connections, connection); +} + +static void +connection_ready_cb (TpConnection *connection, + const GError *error, + gpointer manager) +{ + /* Errors will be handled in invalidated callback */ + if (error != NULL) + return; + + g_signal_emit (manager, signals[NEW_CONNECTION], 0, connection); +} + +static void +account_manager_update_connection (EmpathyAccountManager *manager, + AccountData *data, + McAccount *account) +{ + EmpathyAccountManagerPriv *priv = GET_PRIV (manager); + + if (data->connection) + return; + + data->connection = mission_control_get_tpconnection (priv->mc, account, NULL); + if (data->connection != NULL) + { + g_signal_connect (data->connection, "invalidated", + G_CALLBACK (connection_invalidated_cb), manager); + g_hash_table_insert (priv->connections, g_object_ref (data->connection), + g_object_ref (account)); + tp_connection_call_when_ready (data->connection, connection_ready_cb, + manager); + } +} + static void account_created_cb (McAccountMonitor *mon, gchar *account_name, @@ -132,6 +202,7 @@ account_created_cb (McAccountMonitor *mon, AccountData *data; data = account_data_new_default (priv->mc, account); + g_hash_table_insert (priv->accounts, g_object_ref (account), data); initial_status = mission_control_get_connection_status (priv->mc, account, NULL); @@ -141,12 +212,10 @@ account_created_cb (McAccountMonitor *mon, else if (initial_status == TP_CONNECTION_STATUS_CONNECTING) priv->connecting++; - /* the reference returned by mc_account_lookup is owned by the - * hash table. - */ - g_hash_table_insert (priv->accounts, account, data); + account_manager_update_connection (manager, data, account); g_signal_emit (manager, signals[ACCOUNT_CREATED], 0, account); + g_object_unref (account); } } @@ -313,10 +382,11 @@ account_status_changed_idle_cb (ChangedSignalData *signal_data) if (status == TP_CONNECTION_STATUS_CONNECTED) { - if (data->source_id > 0) { - g_source_remove (data->source_id); - data->source_id = 0; - } + if (data->source_id > 0) + { + g_source_remove (data->source_id); + data->source_id = 0; + } data->source_id = g_timeout_add_seconds (10, remove_data_timeout, @@ -325,6 +395,8 @@ account_status_changed_idle_cb (ChangedSignalData *signal_data) emit_connection = TRUE; } + account_manager_update_connection (manager, data, account); + if (emit_presence) g_signal_emit (manager, signals[ACCOUNT_PRESENCE_CHANGED], 0, account, presence, old_p); @@ -381,6 +453,8 @@ empathy_account_manager_init (EmpathyAccountManager *manager) empathy_account_equal, g_object_unref, (GDestroyNotify) account_data_free); + priv->connections = g_hash_table_new_full (g_direct_hash, g_direct_equal, + g_object_unref, g_object_unref); mc_accounts = mc_accounts_list (); @@ -412,6 +486,7 @@ do_finalize (GObject *obj) EmpathyAccountManagerPriv *priv = GET_PRIV (manager); g_hash_table_unref (priv->accounts); + g_hash_table_unref (priv->connections); G_OBJECT_CLASS (empathy_account_manager_parent_class)->finalize (obj); } @@ -562,6 +637,16 @@ empathy_account_manager_class_init (EmpathyAccountManagerClass *klass) 3, MC_TYPE_ACCOUNT, G_TYPE_INT, /* actual presence */ G_TYPE_INT); /* previous presence */ + + signals[NEW_CONNECTION] = + g_signal_new ("new-connection", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, TP_TYPE_CONNECTION); g_type_class_add_private (oclass, sizeof (EmpathyAccountManagerPriv)); } @@ -634,3 +719,91 @@ empathy_account_manager_get_count (EmpathyAccountManager *manager) return g_hash_table_size (priv->accounts); } + +McAccount * +empathy_account_manager_get_account (EmpathyAccountManager *manager, + TpConnection *connection) +{ + EmpathyAccountManagerPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), 0); + + priv = GET_PRIV (manager); + + return g_hash_table_lookup (priv->connections, connection); +} + +GList * +empathy_account_manager_dup_accounts (EmpathyAccountManager *manager) +{ + EmpathyAccountManagerPriv *priv; + GList *ret; + + g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), NULL); + + priv = GET_PRIV (manager); + + ret = g_hash_table_get_keys (priv->accounts); + g_list_foreach (ret, (GFunc) g_object_ref, NULL); + + return ret; +} + +/** + * empathy_account_manager_get_connection: + * @manager: a #EmpathyAccountManager + * @account: a #McAccount + * + * Get the connection of the accounts, or NULL if account is offline or the + * connection is not yet ready. This function does not return a new ref. + * + * Returns: the connection of the accounts. + **/ +TpConnection * +empathy_account_manager_get_connection (EmpathyAccountManager *manager, + McAccount *account) +{ + EmpathyAccountManagerPriv *priv; + AccountData *data; + + g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), NULL); + g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); + + priv = GET_PRIV (manager); + + data = g_hash_table_lookup (priv->accounts, account); + if (data && data->connection && tp_connection_is_ready (data->connection)) + return data->connection; + + return NULL; +} + +/** + * empathy_account_manager_dup_connections: + * @manager: a #EmpathyAccountManager + * + * Get a #GList of all ready #TpConnection. The list must be freed with + * g_list_free, and its elements must be unreffed. + * + * Returns: the list of connections + **/ +GList * +empathy_account_manager_dup_connections (EmpathyAccountManager *manager) +{ + EmpathyAccountManagerPriv *priv; + GHashTableIter iter; + gpointer connection; + GList *ret = NULL; + + g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), NULL); + + priv = GET_PRIV (manager); + + g_hash_table_iter_init (&iter, priv->connections); + while (g_hash_table_iter_next (&iter, &connection, NULL)) + if (connection != NULL && tp_connection_is_ready (connection)) + ret = g_list_prepend (ret, g_object_ref (connection)); + + return ret; +} + diff --git a/libempathy/empathy-account-manager.h b/libempathy/empathy-account-manager.h index b9aecb09..ac90a34f 100644 --- a/libempathy/empathy-account-manager.h +++ b/libempathy/empathy-account-manager.h @@ -61,6 +61,16 @@ gboolean empathy_account_manager_is_account_just_connected McAccount *account); int empathy_account_manager_get_count (EmpathyAccountManager *manager); +McAccount * empathy_account_manager_get_account + (EmpathyAccountManager *manager, + TpConnection *connection); +GList * empathy_account_manager_dup_accounts + (EmpathyAccountManager *manager); +TpConnection * empathy_account_manager_get_connection + (EmpathyAccountManager *manager, + McAccount *account); +GList * empathy_account_manager_dup_connections + (EmpathyAccountManager *manager); G_END_DECLS diff --git a/libempathy/empathy-call-handler.c b/libempathy/empathy-call-handler.c index 39d5899b..820de6de 100644 --- a/libempathy/empathy-call-handler.c +++ b/libempathy/empathy-call-handler.c @@ -402,30 +402,38 @@ empathy_call_handler_request_cb (EmpathyDispatchOperation *operation, empathy_dispatch_operation_claim (operation); } -static void -empathy_call_handler_contact_ready_cb (EmpathyContact *contact, - const GError *error, gpointer user_data, GObject *object) +void +empathy_call_handler_start_call (EmpathyCallHandler *handler) { - EmpathyCallHandler *self = EMPATHY_CALL_HANDLER (object); - EmpathyCallHandlerPriv *priv = GET_PRIV (self); + + EmpathyCallHandlerPriv *priv = GET_PRIV (handler); EmpathyDispatcher *dispatcher; - McAccount *account; + TpConnection *connection; GStrv allowed; GValue *value; - GHashTable *request = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, - (GDestroyNotify) tp_g_value_slice_free); + GHashTable *request; + + if (priv->call != NULL) + { + empathy_call_handler_start_tpfs (handler); + empathy_tp_call_accept_incoming_call (priv->call); + return; + } g_assert (priv->contact != NULL); dispatcher = empathy_dispatcher_dup_singleton (); - account = empathy_contact_get_account (priv->contact); - allowed = empathy_dispatcher_find_channel_class (dispatcher, account, + connection = empathy_contact_get_connection (priv->contact); + allowed = empathy_dispatcher_find_channel_class (dispatcher, connection, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, TP_HANDLE_TYPE_CONTACT); if (!tp_strv_contains ((const gchar * const *) allowed, TP_IFACE_CHANNEL ".TargetHandle")) return; + request = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, + (GDestroyNotify) tp_g_value_slice_free); + /* org.freedesktop.Telepathy.Channel.ChannelType */ value = tp_g_value_slice_new (G_TYPE_STRING); g_value_set_string (value, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); @@ -441,27 +449,9 @@ empathy_call_handler_contact_ready_cb (EmpathyContact *contact, g_value_set_uint (value, empathy_contact_get_handle (priv->contact)); g_hash_table_insert (request, TP_IFACE_CHANNEL ".TargetHandle", value); - empathy_dispatcher_create_channel (dispatcher, account, - request, empathy_call_handler_request_cb, self); + empathy_dispatcher_create_channel (dispatcher, connection, + request, empathy_call_handler_request_cb, handler); g_object_unref (dispatcher); } -void -empathy_call_handler_start_call (EmpathyCallHandler *handler) -{ - - EmpathyCallHandlerPriv *priv = GET_PRIV (handler); - - if (priv->call == NULL) - { - empathy_contact_call_when_ready (priv->contact, - EMPATHY_CONTACT_READY_HANDLE, - empathy_call_handler_contact_ready_cb, NULL, NULL, G_OBJECT (handler)); - } - else - { - empathy_call_handler_start_tpfs (handler); - empathy_tp_call_accept_incoming_call (priv->call); - } -} diff --git a/libempathy/empathy-chatroom-manager.c b/libempathy/empathy-chatroom-manager.c index 6765d9e4..e57dae7d 100644 --- a/libempathy/empathy-chatroom-manager.c +++ b/libempathy/empathy-chatroom-manager.c @@ -1,7 +1,6 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2004-2007 Imendio AB - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -33,6 +32,7 @@ #include "empathy-tp-chat.h" #include "empathy-chatroom-manager.h" +#include "empathy-account-manager.h" #include "empathy-utils.h" #define DEBUG_FLAG EMPATHY_DEBUG_OTHER @@ -45,26 +45,19 @@ static EmpathyChatroomManager *chatroom_manager_singleton = NULL; #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyChatroomManager) -typedef struct { - GList *chatrooms; +typedef struct +{ + GList *chatrooms; gchar *file; + EmpathyAccountManager *account_manager; /* source id of the autosave timer */ gint save_timer_id; } EmpathyChatroomManagerPriv; -static void chatroom_manager_finalize (GObject *object); -static gboolean chatroom_manager_get_all (EmpathyChatroomManager *manager); -static gboolean chatroom_manager_file_parse (EmpathyChatroomManager *manager, - const gchar *filename); -static void chatroom_manager_parse_chatroom (EmpathyChatroomManager *manager, - xmlNodePtr node); -static gboolean chatroom_manager_file_save (EmpathyChatroomManager *manager); -static void reset_save_timeout (EmpathyChatroomManager *self); - enum { - CHATROOM_ADDED, - CHATROOM_REMOVED, - LAST_SIGNAL + CHATROOM_ADDED, + CHATROOM_REMOVED, + LAST_SIGNAL }; static guint signals[LAST_SIGNAL]; @@ -78,6 +71,238 @@ enum G_DEFINE_TYPE (EmpathyChatroomManager, empathy_chatroom_manager, G_TYPE_OBJECT); +/* + * API to save/load and parse the chatrooms file. + */ + +static gboolean +chatroom_manager_file_save (EmpathyChatroomManager *manager) +{ + EmpathyChatroomManagerPriv *priv; + xmlDocPtr doc; + xmlNodePtr root; + GList *l; + + priv = GET_PRIV (manager); + + doc = xmlNewDoc ("1.0"); + root = xmlNewNode (NULL, "chatrooms"); + xmlDocSetRootElement (doc, root); + + for (l = priv->chatrooms; l; l = l->next) { + EmpathyChatroom *chatroom; + xmlNodePtr node; + const gchar *account_id; + + chatroom = l->data; + + if (!empathy_chatroom_is_favorite (chatroom)) { + continue; + } + + account_id = mc_account_get_unique_name (empathy_chatroom_get_account (chatroom)); + + node = xmlNewChild (root, NULL, "chatroom", NULL); + xmlNewTextChild (node, NULL, "name", empathy_chatroom_get_name (chatroom)); + xmlNewTextChild (node, NULL, "room", empathy_chatroom_get_room (chatroom)); + xmlNewTextChild (node, NULL, "account", account_id); + xmlNewTextChild (node, NULL, "auto_connect", + empathy_chatroom_get_auto_connect (chatroom) ? "yes" : "no"); + } + + /* Make sure the XML is indented properly */ + xmlIndentTreeOutput = 1; + + DEBUG ("Saving file:'%s'", priv->file); + xmlSaveFormatFileEnc (priv->file, doc, "utf-8", 1); + xmlFreeDoc (doc); + + xmlCleanupParser (); + xmlMemoryDump (); + + return TRUE; +} + +static gboolean +save_timeout (EmpathyChatroomManager *self) +{ + EmpathyChatroomManagerPriv *priv = GET_PRIV (self); + + priv->save_timer_id = 0; + chatroom_manager_file_save (self); + + return FALSE; +} + +static void +reset_save_timeout (EmpathyChatroomManager *self) +{ + EmpathyChatroomManagerPriv *priv = GET_PRIV (self); + + if (priv->save_timer_id > 0) + { + g_source_remove (priv->save_timer_id); + } + + priv->save_timer_id = g_timeout_add_seconds (SAVE_TIMER, + (GSourceFunc) save_timeout, self); +} + +static void +chatroom_changed_cb (EmpathyChatroom *chatroom, + GParamSpec *spec, + EmpathyChatroomManager *self) +{ + reset_save_timeout (self); +} + +static void +add_chatroom (EmpathyChatroomManager *self, + EmpathyChatroom *chatroom) +{ + EmpathyChatroomManagerPriv *priv = GET_PRIV (self); + + priv->chatrooms = g_list_prepend (priv->chatrooms, g_object_ref (chatroom)); + + g_signal_connect (chatroom, "notify", + G_CALLBACK (chatroom_changed_cb), self); +} + +static void +chatroom_manager_parse_chatroom (EmpathyChatroomManager *manager, + xmlNodePtr node) +{ + EmpathyChatroomManagerPriv *priv; + EmpathyChatroom *chatroom; + McAccount *account; + xmlNodePtr child; + gchar *str; + gchar *name; + gchar *room; + gchar *account_id; + gboolean auto_connect; + + priv = GET_PRIV (manager); + + /* default values. */ + name = NULL; + room = NULL; + auto_connect = TRUE; + account_id = NULL; + + for (child = node->children; child; child = child->next) { + gchar *tag; + + if (xmlNodeIsText (child)) { + continue; + } + + tag = (gchar *) child->name; + str = (gchar *) xmlNodeGetContent (child); + + if (strcmp (tag, "name") == 0) { + name = g_strdup (str); + } + else if (strcmp (tag, "room") == 0) { + room = g_strdup (str); + } + else if (strcmp (tag, "auto_connect") == 0) { + if (strcmp (str, "yes") == 0) { + auto_connect = TRUE; + } else { + auto_connect = FALSE; + } + } + else if (strcmp (tag, "account") == 0) { + account_id = g_strdup (str); + } + + xmlFree (str); + } + + account = mc_account_lookup (account_id); + if (!account) { + g_free (name); + g_free (room); + g_free (account_id); + return; + } + + chatroom = empathy_chatroom_new_full (account, room, name, auto_connect); + empathy_chatroom_set_favorite (chatroom, TRUE); + add_chatroom (manager, chatroom); + g_signal_emit (manager, signals[CHATROOM_ADDED], 0, chatroom); + + g_object_unref (account); + g_free (name); + g_free (room); + g_free (account_id); +} + +static gboolean +chatroom_manager_file_parse (EmpathyChatroomManager *manager, + const gchar *filename) +{ + EmpathyChatroomManagerPriv *priv; + xmlParserCtxtPtr ctxt; + xmlDocPtr doc; + xmlNodePtr chatrooms; + xmlNodePtr node; + + priv = GET_PRIV (manager); + + DEBUG ("Attempting to parse file:'%s'...", filename); + + ctxt = xmlNewParserCtxt (); + + /* Parse and validate the file. */ + doc = xmlCtxtReadFile (ctxt, filename, NULL, 0); + if (!doc) { + g_warning ("Failed to parse file:'%s'", filename); + xmlFreeParserCtxt (ctxt); + return FALSE; + } + + if (!empathy_xml_validate (doc, CHATROOMS_DTD_FILENAME)) { + g_warning ("Failed to validate file:'%s'", filename); + xmlFreeDoc(doc); + xmlFreeParserCtxt (ctxt); + return FALSE; + } + + /* The root node, chatrooms. */ + chatrooms = xmlDocGetRootElement (doc); + + for (node = chatrooms->children; node; node = node->next) { + if (strcmp ((gchar *) node->name, "chatroom") == 0) { + chatroom_manager_parse_chatroom (manager, node); + } + } + + DEBUG ("Parsed %d chatrooms", g_list_length (priv->chatrooms)); + + xmlFreeDoc(doc); + xmlFreeParserCtxt (ctxt); + + return TRUE; +} + +static gboolean +chatroom_manager_get_all (EmpathyChatroomManager *manager) +{ + EmpathyChatroomManagerPriv *priv; + + priv = GET_PRIV (manager); + + /* read file in */ + if (g_file_test (priv->file, G_FILE_TEST_EXISTS) && + !chatroom_manager_file_parse (manager, priv->file)) { + return FALSE; + } + + return TRUE; +} + static void empathy_chatroom_manager_get_property (GObject *object, guint property_id, @@ -119,6 +344,41 @@ empathy_chatroom_manager_set_property (GObject *object, } } +static void +chatroom_manager_finalize (GObject *object) +{ + EmpathyChatroomManager *self = EMPATHY_CHATROOM_MANAGER (object); + EmpathyChatroomManagerPriv *priv; + GList *l; + + priv = GET_PRIV (object); + + g_object_unref (priv->account_manager); + + if (priv->save_timer_id > 0) + { + /* have to save before destroy the object */ + g_source_remove (priv->save_timer_id); + priv->save_timer_id = 0; + chatroom_manager_file_save (self); + } + + for (l = priv->chatrooms; l != NULL; l = g_list_next (l)) + { + EmpathyChatroom *chatroom = l->data; + + g_signal_handlers_disconnect_by_func (chatroom, chatroom_changed_cb, + self); + + g_object_unref (chatroom); + } + + g_list_free (priv->chatrooms); + g_free (priv->file); + + (G_OBJECT_CLASS (empathy_chatroom_manager_parent_class)->finalize) (object); +} + static GObject * empathy_chatroom_manager_constructor (GType type, guint n_props, @@ -141,6 +401,8 @@ empathy_chatroom_manager_constructor (GType type, chatroom_manager_singleton = self; g_object_add_weak_pointer (obj, (gpointer) &chatroom_manager_singleton); + priv->account_manager = empathy_account_manager_dup_singleton (); + if (priv->file == NULL) { /* Set the default file path */ @@ -152,230 +414,137 @@ empathy_chatroom_manager_constructor (GType type, priv->file = g_build_filename (dir, CHATROOMS_XML_FILENAME, NULL); g_free (dir); - } - - chatroom_manager_get_all (self); - return obj; -} - -static void -empathy_chatroom_manager_class_init (EmpathyChatroomManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GParamSpec *param_spec; - - object_class->constructor = empathy_chatroom_manager_constructor; - object_class->get_property = empathy_chatroom_manager_get_property; - object_class->set_property = empathy_chatroom_manager_set_property; - object_class->finalize = chatroom_manager_finalize; - - param_spec = g_param_spec_string ( - "file", - "path of the favorite file", - "The path of the XML file containing user's favorites", - NULL, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_FILE, param_spec); - - signals[CHATROOM_ADDED] = - g_signal_new ("chatroom-added", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, - 1, EMPATHY_TYPE_CHATROOM); - signals[CHATROOM_REMOVED] = - g_signal_new ("chatroom-removed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, - 1, EMPATHY_TYPE_CHATROOM); - - g_type_class_add_private (object_class, - sizeof (EmpathyChatroomManagerPriv)); -} - -static void -empathy_chatroom_manager_init (EmpathyChatroomManager *manager) -{ - EmpathyChatroomManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, - EMPATHY_TYPE_CHATROOM_MANAGER, EmpathyChatroomManagerPriv); - - manager->priv = priv; -} - -static void -chatroom_changed_cb (EmpathyChatroom *chatroom, - GParamSpec *spec, - EmpathyChatroomManager *self) -{ - reset_save_timeout (self); -} - -static void -chatroom_manager_finalize (GObject *object) -{ - EmpathyChatroomManager *self = EMPATHY_CHATROOM_MANAGER (object); - EmpathyChatroomManagerPriv *priv; - GList *l; - - priv = GET_PRIV (object); - - if (priv->save_timer_id > 0) - { - /* have to save before destroy the object */ - g_source_remove (priv->save_timer_id); - priv->save_timer_id = 0; - chatroom_manager_file_save (self); - } - - for (l = priv->chatrooms; l != NULL; l = g_list_next (l)) - { - EmpathyChatroom *chatroom = l->data; - - g_signal_handlers_disconnect_by_func (chatroom, chatroom_changed_cb, - self); - - g_object_unref (chatroom); - } - - g_list_free (priv->chatrooms); - g_free (priv->file); - - (G_OBJECT_CLASS (empathy_chatroom_manager_parent_class)->finalize) (object); -} - -EmpathyChatroomManager * -empathy_chatroom_manager_dup_singleton (const gchar *file) -{ - return EMPATHY_CHATROOM_MANAGER (g_object_new (EMPATHY_TYPE_CHATROOM_MANAGER, - "file", file, NULL)); -} - -static gboolean -save_timeout (EmpathyChatroomManager *self) -{ - EmpathyChatroomManagerPriv *priv = GET_PRIV (self); - - priv->save_timer_id = 0; - chatroom_manager_file_save (self); + } - return FALSE; + chatroom_manager_get_all (self); + return obj; } static void -reset_save_timeout (EmpathyChatroomManager *self) +empathy_chatroom_manager_class_init (EmpathyChatroomManagerClass *klass) { - EmpathyChatroomManagerPriv *priv = GET_PRIV (self); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GParamSpec *param_spec; - if (priv->save_timer_id > 0) - { - g_source_remove (priv->save_timer_id); - } + object_class->constructor = empathy_chatroom_manager_constructor; + object_class->get_property = empathy_chatroom_manager_get_property; + object_class->set_property = empathy_chatroom_manager_set_property; + object_class->finalize = chatroom_manager_finalize; - priv->save_timer_id = g_timeout_add_seconds (SAVE_TIMER, - (GSourceFunc) save_timeout, self); + param_spec = g_param_spec_string ( + "file", + "path of the favorite file", + "The path of the XML file containing user's favorites", + NULL, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_NICK | + G_PARAM_STATIC_BLURB); + g_object_class_install_property (object_class, PROP_FILE, param_spec); + + signals[CHATROOM_ADDED] = g_signal_new ("chatroom-added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, EMPATHY_TYPE_CHATROOM); + + signals[CHATROOM_REMOVED] = g_signal_new ("chatroom-removed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, EMPATHY_TYPE_CHATROOM); + + g_type_class_add_private (object_class, sizeof (EmpathyChatroomManagerPriv)); } static void -add_chatroom (EmpathyChatroomManager *self, - EmpathyChatroom *chatroom) +empathy_chatroom_manager_init (EmpathyChatroomManager *manager) { - EmpathyChatroomManagerPriv *priv = GET_PRIV (self); + EmpathyChatroomManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, + EMPATHY_TYPE_CHATROOM_MANAGER, EmpathyChatroomManagerPriv); - priv->chatrooms = g_list_prepend (priv->chatrooms, g_object_ref (chatroom)); + manager->priv = priv; +} - g_signal_connect (chatroom, "notify", - G_CALLBACK (chatroom_changed_cb), self); +EmpathyChatroomManager * +empathy_chatroom_manager_dup_singleton (const gchar *file) +{ + return EMPATHY_CHATROOM_MANAGER (g_object_new (EMPATHY_TYPE_CHATROOM_MANAGER, + "file", file, NULL)); } gboolean empathy_chatroom_manager_add (EmpathyChatroomManager *manager, EmpathyChatroom *chatroom) { - EmpathyChatroomManagerPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager), FALSE); - g_return_val_if_fail (EMPATHY_IS_CHATROOM (chatroom), FALSE); - - priv = GET_PRIV (manager); + EmpathyChatroomManagerPriv *priv; - /* don't add more than once */ - if (!empathy_chatroom_manager_find (manager, - empathy_chatroom_get_account (chatroom), - empathy_chatroom_get_room (chatroom))) { - gboolean favorite; + g_return_val_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager), FALSE); + g_return_val_if_fail (EMPATHY_IS_CHATROOM (chatroom), FALSE); - g_object_get (chatroom, "favorite", &favorite, NULL); + priv = GET_PRIV (manager); - add_chatroom (manager, chatroom); + /* don't add more than once */ + if (!empathy_chatroom_manager_find (manager, + empathy_chatroom_get_account (chatroom), + empathy_chatroom_get_room (chatroom))) + { + add_chatroom (manager, chatroom); - if (favorite) - { + if (empathy_chatroom_is_favorite (chatroom)) reset_save_timeout (manager); - } - - g_signal_emit (manager, signals[CHATROOM_ADDED], 0, chatroom); - return TRUE; - } + g_signal_emit (manager, signals[CHATROOM_ADDED], 0, chatroom); + return TRUE; + } - return FALSE; + return FALSE; } void empathy_chatroom_manager_remove (EmpathyChatroomManager *manager, - EmpathyChatroom *chatroom) + EmpathyChatroom *chatroom) { - EmpathyChatroomManagerPriv *priv; - GList *l; - - g_return_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager)); - g_return_if_fail (EMPATHY_IS_CHATROOM (chatroom)); - - priv = GET_PRIV (manager); + EmpathyChatroomManagerPriv *priv; + GList *l; - for (l = priv->chatrooms; l; l = l->next) { - EmpathyChatroom *this_chatroom; + g_return_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager)); + g_return_if_fail (EMPATHY_IS_CHATROOM (chatroom)); - this_chatroom = l->data; + priv = GET_PRIV (manager); - if (this_chatroom == chatroom || - empathy_chatroom_equal (chatroom, this_chatroom)) { - gboolean favorite; - priv->chatrooms = g_list_delete_link (priv->chatrooms, l); + for (l = priv->chatrooms; l; l = l->next) + { + EmpathyChatroom *this_chatroom; - g_object_get (chatroom, "favorite", &favorite, NULL); + this_chatroom = l->data; - if (favorite) + if (this_chatroom == chatroom || + empathy_chatroom_equal (chatroom, this_chatroom)) { - reset_save_timeout (manager); - } - - g_signal_emit (manager, signals[CHATROOM_REMOVED], 0, this_chatroom); + priv->chatrooms = g_list_delete_link (priv->chatrooms, l); + if (empathy_chatroom_is_favorite (chatroom)) + reset_save_timeout (manager); - g_signal_handlers_disconnect_by_func (chatroom, chatroom_changed_cb, - manager); + g_signal_emit (manager, signals[CHATROOM_REMOVED], 0, this_chatroom); + g_signal_handlers_disconnect_by_func (chatroom, chatroom_changed_cb, + manager); - g_object_unref (this_chatroom); - break; - } - } + g_object_unref (this_chatroom); + break; + } + } } EmpathyChatroom * empathy_chatroom_manager_find (EmpathyChatroomManager *manager, - McAccount *account, - const gchar *room) + McAccount *account, + const gchar *room) { EmpathyChatroomManagerPriv *priv; GList *l; @@ -457,7 +626,7 @@ empathy_chatroom_manager_get_count (EmpathyChatroomManager *manager, chatroom = l->data; if (empathy_account_equal (account, - empathy_chatroom_get_account (chatroom))) { + empathy_chatroom_get_account (chatroom))) { count++; } } @@ -465,225 +634,36 @@ empathy_chatroom_manager_get_count (EmpathyChatroomManager *manager, return count; } -/* - * API to save/load and parse the chatrooms file. - */ - -static gboolean -chatroom_manager_get_all (EmpathyChatroomManager *manager) -{ - EmpathyChatroomManagerPriv *priv; - - priv = GET_PRIV (manager); - - /* read file in */ - if (g_file_test (priv->file, G_FILE_TEST_EXISTS) && - !chatroom_manager_file_parse (manager, priv->file)) - return FALSE; - - return TRUE; -} - -static gboolean -chatroom_manager_file_parse (EmpathyChatroomManager *manager, - const gchar *filename) -{ - EmpathyChatroomManagerPriv *priv; - xmlParserCtxtPtr ctxt; - xmlDocPtr doc; - xmlNodePtr chatrooms; - xmlNodePtr node; - - priv = GET_PRIV (manager); - - DEBUG ("Attempting to parse file:'%s'...", filename); - - ctxt = xmlNewParserCtxt (); - - /* Parse and validate the file. */ - doc = xmlCtxtReadFile (ctxt, filename, NULL, 0); - if (!doc) { - g_warning ("Failed to parse file:'%s'", filename); - xmlFreeParserCtxt (ctxt); - return FALSE; - } - - if (!empathy_xml_validate (doc, CHATROOMS_DTD_FILENAME)) { - g_warning ("Failed to validate file:'%s'", filename); - xmlFreeDoc(doc); - xmlFreeParserCtxt (ctxt); - return FALSE; - } - - /* The root node, chatrooms. */ - chatrooms = xmlDocGetRootElement (doc); - - for (node = chatrooms->children; node; node = node->next) { - if (strcmp ((gchar *) node->name, "chatroom") == 0) { - chatroom_manager_parse_chatroom (manager, node); - } - } - - DEBUG ("Parsed %d chatrooms", g_list_length (priv->chatrooms)); - - xmlFreeDoc(doc); - xmlFreeParserCtxt (ctxt); - - return TRUE; -} - -static void -chatroom_manager_parse_chatroom (EmpathyChatroomManager *manager, - xmlNodePtr node) -{ - EmpathyChatroomManagerPriv *priv; - EmpathyChatroom *chatroom; - McAccount *account; - xmlNodePtr child; - gchar *str; - gchar *name; - gchar *room; - gchar *account_id; - gboolean auto_connect; - - priv = GET_PRIV (manager); - - /* default values. */ - name = NULL; - room = NULL; - auto_connect = TRUE; - account_id = NULL; - - for (child = node->children; child; child = child->next) { - gchar *tag; - - if (xmlNodeIsText (child)) { - continue; - } - - tag = (gchar *) child->name; - str = (gchar *) xmlNodeGetContent (child); - - if (strcmp (tag, "name") == 0) { - name = g_strdup (str); - } - else if (strcmp (tag, "room") == 0) { - room = g_strdup (str); - } - else if (strcmp (tag, "auto_connect") == 0) { - if (strcmp (str, "yes") == 0) { - auto_connect = TRUE; - } else { - auto_connect = FALSE; - } - } - else if (strcmp (tag, "account") == 0) { - account_id = g_strdup (str); - } - - xmlFree (str); - } - - account = mc_account_lookup (account_id); - if (!account) { - g_free (name); - g_free (room); - g_free (account_id); - return; - } - - chatroom = empathy_chatroom_new_full (account, room, name, auto_connect); - g_object_set (chatroom, "favorite", TRUE, NULL); - add_chatroom (manager, chatroom); - g_signal_emit (manager, signals[CHATROOM_ADDED], 0, chatroom); - - g_object_unref (account); - g_free (name); - g_free (room); - g_free (account_id); -} - -static gboolean -chatroom_manager_file_save (EmpathyChatroomManager *manager) -{ - EmpathyChatroomManagerPriv *priv; - xmlDocPtr doc; - xmlNodePtr root; - GList *l; - - priv = GET_PRIV (manager); - - doc = xmlNewDoc ("1.0"); - root = xmlNewNode (NULL, "chatrooms"); - xmlDocSetRootElement (doc, root); - - for (l = priv->chatrooms; l; l = l->next) { - EmpathyChatroom *chatroom; - xmlNodePtr node; - const gchar *account_id; - gboolean favorite; - - chatroom = l->data; - - g_object_get (chatroom, "favorite", &favorite, NULL); - if (!favorite) - continue; - - account_id = mc_account_get_unique_name (empathy_chatroom_get_account (chatroom)); - - node = xmlNewChild (root, NULL, "chatroom", NULL); - xmlNewTextChild (node, NULL, "name", empathy_chatroom_get_name (chatroom)); - xmlNewTextChild (node, NULL, "room", empathy_chatroom_get_room (chatroom)); - xmlNewTextChild (node, NULL, "account", account_id); - xmlNewTextChild (node, NULL, "auto_connect", empathy_chatroom_get_auto_connect (chatroom) ? "yes" : "no"); - } - - /* Make sure the XML is indented properly */ - xmlIndentTreeOutput = 1; - - DEBUG ("Saving file:'%s'", priv->file); - xmlSaveFormatFileEnc (priv->file, doc, "utf-8", 1); - xmlFreeDoc (doc); - - xmlCleanupParser (); - xmlMemoryDump (); - - return TRUE; -} - static void chatroom_manager_chat_destroyed_cb (EmpathyTpChat *chat, - gpointer user_data) + gpointer manager) { - EmpathyChatroomManager *manager = EMPATHY_CHATROOM_MANAGER (user_data); - McAccount *account = empathy_tp_chat_get_account (chat); - EmpathyChatroom *chatroom; - const gchar *roomname; - gboolean favorite; - - roomname = empathy_tp_chat_get_id (chat); - chatroom = empathy_chatroom_manager_find (manager, account, roomname); + EmpathyChatroomManagerPriv *priv = GET_PRIV (manager); + GList *l; - if (chatroom == NULL) - return; + for (l = priv->chatrooms; l; l = l->next) + { + EmpathyChatroom *chatroom = l->data; - g_object_set (chatroom, "tp-chat", NULL, NULL); - g_object_get (chatroom, "favorite", &favorite, NULL); + if (empathy_chatroom_get_tp_chat (chatroom) != chat) + continue; - if (!favorite) - { - /* Remove the chatroom from the list, unless it's in the list of - * favourites.. - * FIXME this policy should probably not be in libempathy */ - empathy_chatroom_manager_remove (manager, chatroom); + empathy_chatroom_set_tp_chat (chatroom, NULL); + if (!empathy_chatroom_is_favorite (chatroom)) + { + /* Remove the chatroom from the list, unless it's in the list of + * favourites.. + * FIXME this policy should probably not be in libempathy */ + empathy_chatroom_manager_remove (manager, chatroom); + } } } static void chatroom_manager_observe_channel_cb (EmpathyDispatcher *dispatcher, - EmpathyDispatchOperation *operation, gpointer user_data) + EmpathyDispatchOperation *operation, gpointer manager) { - EmpathyChatroomManager *manager = EMPATHY_CHATROOM_MANAGER (user_data); + EmpathyChatroomManagerPriv *priv = GET_PRIV (manager); EmpathyChatroom *chatroom; TpChannel *channel; EmpathyTpChat *chat; @@ -691,6 +671,7 @@ chatroom_manager_observe_channel_cb (EmpathyDispatcher *dispatcher, GQuark channel_type; TpHandleType handle_type; McAccount *account; + TpConnection *connection; channel_type = empathy_dispatch_operation_get_channel_type_id (operation); @@ -706,7 +687,9 @@ chatroom_manager_observe_channel_cb (EmpathyDispatcher *dispatcher, chat = EMPATHY_TP_CHAT ( empathy_dispatch_operation_get_channel_wrapper (operation)); - account = empathy_tp_chat_get_account (chat); + connection = empathy_tp_chat_get_connection (chat); + account = empathy_account_manager_get_account (priv->account_manager, + connection); roomname = empathy_tp_chat_get_id (chat); @@ -716,13 +699,13 @@ chatroom_manager_observe_channel_cb (EmpathyDispatcher *dispatcher, { chatroom = empathy_chatroom_new_full (account, roomname, roomname, FALSE); - g_object_set (G_OBJECT (chatroom), "tp-chat", chat, NULL); + empathy_chatroom_set_tp_chat (chatroom, chat); empathy_chatroom_manager_add (manager, chatroom); g_object_unref (chatroom); } else { - g_object_set (G_OBJECT (chatroom), "tp-chat", chat, NULL); + empathy_chatroom_set_tp_chat (chatroom, chat); } /* A TpChat is always destroyed as it only gets unreffed after the channel diff --git a/libempathy/empathy-chatroom.c b/libempathy/empathy-chatroom.c index 8ffd8a51..6575bb99 100644 --- a/libempathy/empathy-chatroom.c +++ b/libempathy/empathy-chatroom.c @@ -111,17 +111,14 @@ empathy_chatroom_class_init (EmpathyChatroomClass *klass) FALSE, G_PARAM_READWRITE)); - g_object_class_install_property (object_class, - PROP_FAVORITE, - g_param_spec_boolean ("favorite", - "Favorite", - "TRUE if the chatroom is in user's favorite list", - FALSE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); + g_object_class_install_property (object_class, + PROP_FAVORITE, + g_param_spec_boolean ("favorite", + "Favorite", + "TRUE if the chatroom is in user's favorite list", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_TP_CHAT, @@ -284,30 +281,14 @@ chatroom_set_property (GObject *object, empathy_chatroom_set_auto_connect (EMPATHY_CHATROOM (object), g_value_get_boolean (value)); break; - case PROP_FAVORITE: - priv->favorite = g_value_get_boolean (value); - if (!priv->favorite) - { - empathy_chatroom_set_auto_connect (EMPATHY_CHATROOM (object), - FALSE); - } - break; - case PROP_TP_CHAT: { - GObject *chat = g_value_dup_object (value); - - if (chat == (GObject *) priv->tp_chat) - break; - - g_assert (chat == NULL || priv->tp_chat == NULL); - - if (priv->tp_chat != NULL) { - g_object_unref (priv->tp_chat); - priv->tp_chat = NULL; - } else { - priv->tp_chat = EMPATHY_TP_CHAT (chat); - } + case PROP_FAVORITE: + empathy_chatroom_set_favorite (EMPATHY_CHATROOM (object), + g_value_get_boolean (value)); + break; + case PROP_TP_CHAT: + empathy_chatroom_set_tp_chat (EMPATHY_CHATROOM (object), + g_value_get_object (value)); break; - } case PROP_SUBJECT: empathy_chatroom_set_subject (EMPATHY_CHATROOM (object), g_value_get_string (value)); @@ -476,12 +457,11 @@ empathy_chatroom_set_auto_connect (EmpathyChatroom *chatroom, priv->auto_connect = auto_connect; - if (priv->auto_connect) - { - /* auto_connect implies favorite */ - priv->favorite = TRUE; - g_object_notify (G_OBJECT (chatroom), "favorite"); - } + if (priv->auto_connect) { + /* auto_connect implies favorite */ + priv->favorite = TRUE; + g_object_notify (G_OBJECT (chatroom), "favorite"); + } g_object_notify (G_OBJECT (chatroom), "auto-connect"); } @@ -504,12 +484,13 @@ empathy_chatroom_equal (gconstpointer v1, room_a = empathy_chatroom_get_room (EMPATHY_CHATROOM (v1)); room_b = empathy_chatroom_get_room (EMPATHY_CHATROOM (v2)); - return empathy_account_equal (account_a, account_b) && !tp_strdiff (room_a, - room_b); + return empathy_account_equal (account_a, account_b) && + !tp_strdiff (room_a, room_b); } EmpathyTpChat * -empathy_chatroom_get_tp_chat (EmpathyChatroom *chatroom) { +empathy_chatroom_get_tp_chat (EmpathyChatroom *chatroom) +{ EmpathyChatroomPriv *priv; g_return_val_if_fail (EMPATHY_IS_CHATROOM (chatroom), NULL); @@ -631,3 +612,59 @@ empathy_chatroom_set_invite_only (EmpathyChatroom *chatroom, g_object_notify (G_OBJECT (chatroom), "invite-only"); } +void +empathy_chatroom_set_tp_chat (EmpathyChatroom *chatroom, + EmpathyTpChat *tp_chat) +{ + EmpathyChatroomPriv *priv; + + g_return_if_fail (EMPATHY_IS_CHATROOM (chatroom)); + g_return_if_fail (tp_chat == NULL || EMPATHY_IS_TP_CHAT (tp_chat)); + + priv = GET_PRIV (chatroom); + + if (priv->tp_chat == tp_chat) { + return; + } + + if (priv->tp_chat != NULL) { + g_object_unref (priv->tp_chat); + } + + priv->tp_chat = tp_chat ? g_object_ref (tp_chat) : NULL; + g_object_notify (G_OBJECT (chatroom), "tp-chat"); +} + +gboolean +empathy_chatroom_is_favorite (EmpathyChatroom *chatroom) +{ + EmpathyChatroomPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CHATROOM (chatroom), FALSE); + + priv = GET_PRIV (chatroom); + + return priv->favorite; +} + +void +empathy_chatroom_set_favorite (EmpathyChatroom *chatroom, + gboolean favorite) +{ + EmpathyChatroomPriv *priv; + + g_return_if_fail (EMPATHY_IS_CHATROOM (chatroom)); + + priv = GET_PRIV (chatroom); + + if (priv->favorite == favorite) { + return; + } + + priv->favorite = favorite; + if (!priv->favorite) { + empathy_chatroom_set_auto_connect (chatroom, FALSE); + } + g_object_notify (G_OBJECT (chatroom), "favorite"); +} + diff --git a/libempathy/empathy-chatroom.h b/libempathy/empathy-chatroom.h index 08e3bc1e..560517d4 100644 --- a/libempathy/empathy-chatroom.h +++ b/libempathy/empathy-chatroom.h @@ -84,6 +84,11 @@ void empathy_chatroom_set_invite_only (EmpathyChatroom *chatroom, gboolean empathy_chatroom_equal (gconstpointer v1, gconstpointer v2); EmpathyTpChat * empathy_chatroom_get_tp_chat (EmpathyChatroom *chatroom); +void empathy_chatroom_set_tp_chat (EmpathyChatroom *chatroom, + EmpathyTpChat *tp_chat); +gboolean empathy_chatroom_is_favorite (EmpathyChatroom *chatroom); +void empathy_chatroom_set_favorite (EmpathyChatroom *chatroom, + gboolean favorite); G_END_DECLS diff --git a/libempathy/empathy-contact-factory.c b/libempathy/empathy-contact-factory.c deleted file mode 100644 index c3500577..00000000 --- a/libempathy/empathy-contact-factory.c +++ /dev/null @@ -1,187 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2007-2008 Collabora Ltd. - * - * This library 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.1 of the License, or (at your option) any later version. - * - * This library 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 library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Authors: Xavier Claessens - */ - -#include - -#include "empathy-contact-factory.h" -#include "empathy-utils.h" - -#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyContactFactory) -typedef struct { - GHashTable *accounts; -} EmpathyContactFactoryPriv; - -G_DEFINE_TYPE (EmpathyContactFactory, empathy_contact_factory, G_TYPE_OBJECT); - -static EmpathyContactFactory * factory_singleton = NULL; - -EmpathyTpContactFactory * -empathy_contact_factory_get_tp_factory (EmpathyContactFactory *factory, - McAccount *account) -{ - EmpathyContactFactoryPriv *priv = GET_PRIV (factory); - EmpathyTpContactFactory *tp_factory; - - tp_factory = g_hash_table_lookup (priv->accounts, account); - if (!tp_factory) { - tp_factory = empathy_tp_contact_factory_new (account); - g_hash_table_insert (priv->accounts, account, tp_factory); - } - - return g_object_ref (tp_factory); -} - -EmpathyContact * -empathy_contact_factory_get_user (EmpathyContactFactory *factory, - McAccount *account) -{ - EmpathyTpContactFactory *tp_factory; - - tp_factory = empathy_contact_factory_get_tp_factory (factory, account); - - return empathy_tp_contact_factory_get_user (tp_factory); -} - -EmpathyContact * -empathy_contact_factory_get_from_id (EmpathyContactFactory *factory, - McAccount *account, - const gchar *id) -{ - EmpathyTpContactFactory *tp_factory; - - tp_factory = empathy_contact_factory_get_tp_factory (factory, account); - - return empathy_tp_contact_factory_get_from_id (tp_factory, id); -} - -EmpathyContact * -empathy_contact_factory_get_from_handle (EmpathyContactFactory *factory, - McAccount *account, - guint handle) -{ - EmpathyTpContactFactory *tp_factory; - - tp_factory = empathy_contact_factory_get_tp_factory (factory, account); - - return empathy_tp_contact_factory_get_from_handle (tp_factory, handle); -} - -GList * -empathy_contact_factory_get_from_handles (EmpathyContactFactory *factory, - McAccount *account, - const GArray *handles) -{ - EmpathyTpContactFactory *tp_factory; - - tp_factory = empathy_contact_factory_get_tp_factory (factory, account); - - return empathy_tp_contact_factory_get_from_handles (tp_factory, handles); -} - -void -empathy_contact_factory_set_alias (EmpathyContactFactory *factory, - EmpathyContact *contact, - const gchar *alias) -{ - EmpathyTpContactFactory *tp_factory; - McAccount *account; - - account = empathy_contact_get_account (contact); - tp_factory = empathy_contact_factory_get_tp_factory (factory, account); - - return empathy_tp_contact_factory_set_alias (tp_factory, contact, alias); -} - -void -empathy_contact_factory_set_avatar (EmpathyContactFactory *factory, - McAccount *account, - const gchar *data, - gsize size, - const gchar *mime_type) -{ - EmpathyTpContactFactory *tp_factory; - - tp_factory = empathy_contact_factory_get_tp_factory (factory, account); - - return empathy_tp_contact_factory_set_avatar (tp_factory, - data, size, mime_type); -} - -static void -contact_factory_finalize (GObject *object) -{ - EmpathyContactFactoryPriv *priv = GET_PRIV (object); - - g_hash_table_destroy (priv->accounts); - - G_OBJECT_CLASS (empathy_contact_factory_parent_class)->finalize (object); -} - -static GObject * -contact_factory_constructor (GType type, - guint n_props, - GObjectConstructParam *props) -{ - GObject *retval; - - if (factory_singleton) { - retval = g_object_ref (factory_singleton); - } else { - retval = G_OBJECT_CLASS (empathy_contact_factory_parent_class)->constructor - (type, n_props, props); - - factory_singleton = EMPATHY_CONTACT_FACTORY (retval); - g_object_add_weak_pointer (retval, (gpointer) &factory_singleton); - } - - return retval; -} - -static void -empathy_contact_factory_class_init (EmpathyContactFactoryClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = contact_factory_finalize; - object_class->constructor = contact_factory_constructor; - - g_type_class_add_private (object_class, sizeof (EmpathyContactFactoryPriv)); -} - -static void -empathy_contact_factory_init (EmpathyContactFactory *factory) -{ - EmpathyContactFactoryPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (factory, - EMPATHY_TYPE_CONTACT_FACTORY, EmpathyContactFactoryPriv); - - factory->priv = priv; - priv->accounts = g_hash_table_new_full (empathy_account_hash, - empathy_account_equal, - g_object_unref, - g_object_unref); -} - -EmpathyContactFactory * -empathy_contact_factory_dup_singleton (void) -{ - return g_object_new (EMPATHY_TYPE_CONTACT_FACTORY, NULL); -} - diff --git a/libempathy/empathy-contact-factory.h b/libempathy/empathy-contact-factory.h deleted file mode 100644 index 16df02bc..00000000 --- a/libempathy/empathy-contact-factory.h +++ /dev/null @@ -1,79 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2007-2008 Collabora Ltd. - * - * This library 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.1 of the License, or (at your option) any later version. - * - * This library 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 library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Authors: Xavier Claessens - */ - -#ifndef __EMPATHY_CONTACT_FACTORY_H__ -#define __EMPATHY_CONTACT_FACTORY_H__ - -#include - -#include - -#include "empathy-contact.h" -#include "empathy-tp-contact-factory.h" - -G_BEGIN_DECLS - -#define EMPATHY_TYPE_CONTACT_FACTORY (empathy_contact_factory_get_type ()) -#define EMPATHY_CONTACT_FACTORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_CONTACT_FACTORY, EmpathyContactFactory)) -#define EMPATHY_CONTACT_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_CONTACT_FACTORY, EmpathyContactFactoryClass)) -#define EMPATHY_IS_CONTACT_FACTORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_CONTACT_FACTORY)) -#define EMPATHY_IS_CONTACT_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_CONTACT_FACTORY)) -#define EMPATHY_CONTACT_FACTORY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_CONTACT_FACTORY, EmpathyContactFactoryClass)) - -typedef struct _EmpathyContactFactory EmpathyContactFactory; -typedef struct _EmpathyContactFactoryClass EmpathyContactFactoryClass; - -struct _EmpathyContactFactory { - GObject parent; - gpointer priv; -}; - -struct _EmpathyContactFactoryClass { - GObjectClass parent_class; -}; - -GType empathy_contact_factory_get_type (void) G_GNUC_CONST; -EmpathyContactFactory *empathy_contact_factory_dup_singleton (void); -EmpathyTpContactFactory *empathy_contact_factory_get_tp_factory (EmpathyContactFactory *factory, - McAccount *account); -EmpathyContact * empathy_contact_factory_get_user (EmpathyContactFactory *factory, - McAccount *account); -EmpathyContact * empathy_contact_factory_get_from_id (EmpathyContactFactory *factory, - McAccount *account, - const gchar *id); -EmpathyContact * empathy_contact_factory_get_from_handle (EmpathyContactFactory *factory, - McAccount *account, - guint handle); -GList * empathy_contact_factory_get_from_handles (EmpathyContactFactory *factory, - McAccount *account, - const GArray *handles); -void empathy_contact_factory_set_alias (EmpathyContactFactory *factory, - EmpathyContact *contact, - const gchar *alias); -void empathy_contact_factory_set_avatar (EmpathyContactFactory *factory, - McAccount *account, - const gchar *data, - gsize size, - const gchar *mime_type); - -G_END_DECLS - -#endif /* __EMPATHY_CONTACT_FACTORY_H__ */ diff --git a/libempathy/empathy-contact-manager.c b/libempathy/empathy-contact-manager.c index 409f41c4..66c4514a 100644 --- a/libempathy/empathy-contact-manager.c +++ b/libempathy/empathy-contact-manager.c @@ -86,9 +86,6 @@ contact_manager_groups_changed_cb (EmpathyTpContactList *list, contact, group, is_member); } -static void contact_manager_destroy_cb (EmpathyTpContactList *list, - EmpathyContactManager *manager); - static void contact_manager_disconnect_foreach (gpointer key, gpointer value, @@ -107,75 +104,60 @@ contact_manager_disconnect_foreach (gpointer key, g_signal_handlers_disconnect_by_func (list, contact_manager_groups_changed_cb, manager); - g_signal_handlers_disconnect_by_func (list, - contact_manager_destroy_cb, - manager); } static void -contact_manager_destroy_cb (EmpathyTpContactList *list, - EmpathyContactManager *manager) +contact_manager_invalidated_cb (TpProxy *connection, + guint domain, + gint code, + gchar *message, + EmpathyContactManager *manager) { EmpathyContactManagerPriv *priv = GET_PRIV (manager); - McAccount *account; + EmpathyTpContactList *list; - account = empathy_tp_contact_list_get_account (list); + DEBUG ("Removing connection: %s (%s)", + tp_proxy_get_object_path (TP_PROXY (connection)), + message); - DEBUG ("Removing account: %s", mc_account_get_display_name (account)); - - contact_manager_disconnect_foreach (account, list, manager); - g_hash_table_remove (priv->lists, account); + list = g_hash_table_lookup (priv->lists, connection); + if (list) { + empathy_tp_contact_list_remove_all (list); + g_hash_table_remove (priv->lists, connection); + } } static void -contact_manager_add_account (EmpathyContactManager *manager, - McAccount *account) +contact_manager_new_connection_cb (EmpathyAccountManager *account_manager, + TpConnection *connection, + EmpathyContactManager *self) { - EmpathyContactManagerPriv *priv = GET_PRIV (manager); + EmpathyContactManagerPriv *priv = GET_PRIV (self); EmpathyTpContactList *list; - if (g_hash_table_lookup (priv->lists, account)) { + if (g_hash_table_lookup (priv->lists, connection)) { return; } - DEBUG ("Adding new account: %s", mc_account_get_display_name (account)); - - list = empathy_tp_contact_list_new (account); - if (!list) { - return; - } + DEBUG ("Adding new connection: %s", + tp_proxy_get_object_path (TP_PROXY (connection))); - g_hash_table_insert (priv->lists, g_object_ref (account), list); + list = empathy_tp_contact_list_new (connection); + g_hash_table_insert (priv->lists, g_object_ref (connection), list); + g_signal_connect (connection, "invalidated", + G_CALLBACK (contact_manager_invalidated_cb), + self); /* Connect signals */ g_signal_connect (list, "members-changed", G_CALLBACK (contact_manager_members_changed_cb), - manager); + self); g_signal_connect (list, "pendings-changed", G_CALLBACK (contact_manager_pendings_changed_cb), - manager); + self); g_signal_connect (list, "groups-changed", G_CALLBACK (contact_manager_groups_changed_cb), - manager); - g_signal_connect (list, "destroy", - G_CALLBACK (contact_manager_destroy_cb), - manager); -} - -static void -contact_manager_connection_changed_cb (EmpathyAccountManager *account_manager, - McAccount *account, - TpConnectionStatusReason reason, - TpConnectionStatus current, - TpConnectionStatus previous, - EmpathyContactManager *manager) -{ - if (current != TP_CONNECTION_STATUS_CONNECTED) { - /* We only care about newly connected accounts */ - return; - } - - contact_manager_add_account (manager, account); + self); } static void @@ -189,7 +171,7 @@ contact_manager_finalize (GObject *object) g_hash_table_destroy (priv->lists); g_signal_handlers_disconnect_by_func (priv->account_manager, - contact_manager_connection_changed_cb, + contact_manager_new_connection_cb, object); g_object_unref (priv->account_manager); @@ -232,34 +214,30 @@ empathy_contact_manager_class_init (EmpathyContactManagerClass *klass) static void empathy_contact_manager_init (EmpathyContactManager *manager) { - GSList *accounts, *l; - MissionControl *mc; + GList *connections, *l; EmpathyContactManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, EMPATHY_TYPE_CONTACT_MANAGER, EmpathyContactManagerPriv); manager->priv = priv; - priv->lists = g_hash_table_new_full (empathy_account_hash, - empathy_account_equal, + priv->lists = g_hash_table_new_full (empathy_proxy_hash, + empathy_proxy_equal, (GDestroyNotify) g_object_unref, (GDestroyNotify) g_object_unref); priv->account_manager = empathy_account_manager_dup_singleton (); priv->contact_monitor = NULL; - g_signal_connect (priv->account_manager, - "account-connection-changed", - G_CALLBACK (contact_manager_connection_changed_cb), manager); - - mc = empathy_mission_control_dup_singleton (); + g_signal_connect (priv->account_manager, "new-connection", + G_CALLBACK (contact_manager_new_connection_cb), + manager); /* Get ContactList for existing connections */ - accounts = mission_control_get_online_connections (mc, NULL); - for (l = accounts; l; l = l->next) { - contact_manager_add_account (manager, l->data); + connections = empathy_account_manager_dup_connections (priv->account_manager); + for (l = connections; l; l = l->next) { + contact_manager_new_connection_cb (priv->account_manager, + l->data, manager); g_object_unref (l->data); } - - g_slist_free (accounts); - g_object_unref (mc); + g_list_free (connections); } EmpathyContactManager * @@ -270,14 +248,14 @@ empathy_contact_manager_dup_singleton (void) EmpathyTpContactList * empathy_contact_manager_get_list (EmpathyContactManager *manager, - McAccount *account) + TpConnection *connection) { EmpathyContactManagerPriv *priv = GET_PRIV (manager); g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL); - g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); + g_return_val_if_fail (TP_IS_CONNECTION (connection), NULL); - return g_hash_table_lookup (priv->lists, account); + return g_hash_table_lookup (priv->lists, connection); } static void @@ -287,12 +265,12 @@ contact_manager_add (EmpathyContactList *manager, { EmpathyContactManagerPriv *priv = GET_PRIV (manager); EmpathyContactList *list; - McAccount *account; + TpConnection *connection; g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - account = empathy_contact_get_account (contact); - list = g_hash_table_lookup (priv->lists, account); + connection = empathy_contact_get_connection (contact); + list = g_hash_table_lookup (priv->lists, connection); if (list) { empathy_contact_list_add (list, contact, message); @@ -301,17 +279,17 @@ contact_manager_add (EmpathyContactList *manager, static void contact_manager_remove (EmpathyContactList *manager, - EmpathyContact *contact, + EmpathyContact *contact, const gchar *message) { EmpathyContactManagerPriv *priv = GET_PRIV (manager); EmpathyContactList *list; - McAccount *account; + TpConnection *connection; g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - account = empathy_contact_get_account (contact); - list = g_hash_table_lookup (priv->lists, account); + connection = empathy_contact_get_connection (contact); + list = g_hash_table_lookup (priv->lists, connection); if (list) { empathy_contact_list_remove (list, contact, message); @@ -319,7 +297,7 @@ contact_manager_remove (EmpathyContactList *manager, } static void -contact_manager_get_members_foreach (McAccount *account, +contact_manager_get_members_foreach (TpConnection *connection, EmpathyTpContactList *list, GList **contacts) { @@ -357,7 +335,7 @@ contact_manager_get_monitor (EmpathyContactList *manager) } static void -contact_manager_get_pendings_foreach (McAccount *account, +contact_manager_get_pendings_foreach (TpConnection *connection, EmpathyTpContactList *list, GList **contacts) { @@ -383,7 +361,7 @@ contact_manager_get_pendings (EmpathyContactList *manager) } static void -contact_manager_get_all_groups_foreach (McAccount *account, +contact_manager_get_all_groups_foreach (TpConnection *connection, EmpathyTpContactList *list, GList **all_groups) { @@ -424,12 +402,12 @@ contact_manager_get_groups (EmpathyContactList *manager, { EmpathyContactManagerPriv *priv = GET_PRIV (manager); EmpathyContactList *list; - McAccount *account; + TpConnection *connection; g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL); - account = empathy_contact_get_account (contact); - list = g_hash_table_lookup (priv->lists, account); + connection = empathy_contact_get_connection (contact); + list = g_hash_table_lookup (priv->lists, connection); if (list) { return empathy_contact_list_get_groups (list, contact); @@ -445,12 +423,12 @@ contact_manager_add_to_group (EmpathyContactList *manager, { EmpathyContactManagerPriv *priv = GET_PRIV (manager); EmpathyContactList *list; - McAccount *account; + TpConnection *connection; g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - account = empathy_contact_get_account (contact); - list = g_hash_table_lookup (priv->lists, account); + connection = empathy_contact_get_connection (contact); + list = g_hash_table_lookup (priv->lists, connection); if (list) { empathy_contact_list_add_to_group (list, contact, group); @@ -464,12 +442,12 @@ contact_manager_remove_from_group (EmpathyContactList *manager, { EmpathyContactManagerPriv *priv = GET_PRIV (manager); EmpathyContactList *list; - McAccount *account; + TpConnection *connection; g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - account = empathy_contact_get_account (contact); - list = g_hash_table_lookup (priv->lists, account); + connection = empathy_contact_get_connection (contact); + list = g_hash_table_lookup (priv->lists, connection); if (list) { empathy_contact_list_remove_from_group (list, contact, group); @@ -482,7 +460,7 @@ typedef struct { } RenameGroupData; static void -contact_manager_rename_group_foreach (McAccount *account, +contact_manager_rename_group_foreach (TpConnection *connection, EmpathyTpContactList *list, RenameGroupData *data) { @@ -508,7 +486,7 @@ contact_manager_rename_group (EmpathyContactList *manager, &data); } -static void contact_manager_remove_group_foreach (McAccount *account, +static void contact_manager_remove_group_foreach (TpConnection *connection, EmpathyTpContactList *list, const gchar *group) { @@ -547,14 +525,14 @@ contact_manager_iface_init (EmpathyContactListIface *iface) gboolean empathy_contact_manager_can_add (EmpathyContactManager *manager, - McAccount *account) + TpConnection *connection) { EmpathyContactManagerPriv *priv = GET_PRIV (manager); EmpathyTpContactList *list; g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), FALSE); - list = g_hash_table_lookup (priv->lists, account); + list = g_hash_table_lookup (priv->lists, connection); if (list == NULL) return FALSE; diff --git a/libempathy/empathy-contact-manager.h b/libempathy/empathy-contact-manager.h index 57e8764e..fbe9e2df 100644 --- a/libempathy/empathy-contact-manager.h +++ b/libempathy/empathy-contact-manager.h @@ -24,8 +24,6 @@ #include -#include - #include "empathy-contact.h" #include "empathy-tp-contact-list.h" #include "empathy-contact-list.h" @@ -54,9 +52,9 @@ struct _EmpathyContactManagerClass { GType empathy_contact_manager_get_type (void) G_GNUC_CONST; EmpathyContactManager *empathy_contact_manager_dup_singleton (void); EmpathyTpContactList * empathy_contact_manager_get_list (EmpathyContactManager *manager, - McAccount *account); + TpConnection *connection); gboolean empathy_contact_manager_can_add (EmpathyContactManager *manager, - McAccount *account); + TpConnection *connection); G_END_DECLS diff --git a/libempathy/empathy-contact.c b/libempathy/empathy-contact.c index 1cac4851..fe8cf823 100644 --- a/libempathy/empathy-contact.c +++ b/libempathy/empathy-contact.c @@ -1,27 +1,22 @@ /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ /* - * Copyright (C) 2004 Imendio AB - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. + * This library 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.1 of the License, or (at your option) any later version. * - * This program is distributed in the hope that it will be useful, + * This library 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 - * General Public License for more details. + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * - * Authors: Mikael Hallendal - * Martyn Russell - * Xavier Claessens - * Sjoerd Simons + * Authors: Xavier Claessens */ #include "config.h" @@ -34,7 +29,7 @@ #include #include "empathy-contact.h" -#include "empathy-contact-factory.h" +#include "empathy-account-manager.h" #include "empathy-utils.h" #include "empathy-enum-types.h" #include "empathy-marshal.h" @@ -44,29 +39,19 @@ #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyContact) typedef struct { - EmpathyContactFactory *factory; + TpContact *tp_contact; + McAccount *account; gchar *id; gchar *name; EmpathyAvatar *avatar; - McAccount *account; McPresence presence; gchar *presence_message; guint handle; EmpathyCapabilities capabilities; gboolean is_user; guint hash; - EmpathyContactReady ready; - GList *ready_callbacks; } EmpathyContactPriv; -typedef struct { - EmpathyContactReady ready; - EmpathyContactReadyCb *callback; - gpointer user_data; - GDestroyNotify destroy; - GObject *weak_object; -} ReadyCbData; - static void contact_finalize (GObject *object); static void contact_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec); @@ -78,16 +63,16 @@ G_DEFINE_TYPE (EmpathyContact, empathy_contact, G_TYPE_OBJECT); enum { PROP_0, + PROP_TP_CONTACT, + PROP_ACCOUNT, PROP_ID, PROP_NAME, PROP_AVATAR, - PROP_ACCOUNT, PROP_PRESENCE, PROP_PRESENCE_MESSAGE, PROP_HANDLE, PROP_CAPABILITIES, PROP_IS_USER, - PROP_READY }; enum { @@ -97,19 +82,49 @@ enum { static guint signals[LAST_SIGNAL]; +static void +tp_contact_notify_cb (TpContact *tp_contact, + GParamSpec *param, + GObject *contact) +{ + EmpathyContactPriv *priv = GET_PRIV (contact); + + /* Forward property notifications */ + if (!tp_strdiff (param->name, "alias")) + g_object_notify (contact, "name"); + else if (!tp_strdiff (param->name, "presence-type")) { + McPresence presence; + + presence = empathy_contact_get_presence (EMPATHY_CONTACT (contact)); + g_signal_emit (contact, signals[PRESENCE_CHANGED], 0, presence, priv->presence); + priv->presence = presence; + g_object_notify (contact, "presence"); + } + else if (!tp_strdiff (param->name, "presence-message")) + g_object_notify (contact, "presence-message"); + else if (!tp_strdiff (param->name, "identifier")) + g_object_notify (contact, "id"); + else if (!tp_strdiff (param->name, "handle")) + g_object_notify (contact, "handle"); +} + static void contact_dispose (GObject *object) { EmpathyContactPriv *priv = GET_PRIV (object); + if (priv->tp_contact) + { + g_signal_handlers_disconnect_by_func (priv->tp_contact, + tp_contact_notify_cb, object); + g_object_unref (priv->tp_contact); + } + priv->tp_contact = NULL; + if (priv->account) g_object_unref (priv->account); priv->account = NULL; - if (priv->factory) - g_object_unref (priv->factory); - priv->factory = NULL; - G_OBJECT_CLASS (empathy_contact_parent_class)->dispose (object); } @@ -125,13 +140,29 @@ empathy_contact_class_init (EmpathyContactClass *class) object_class->get_property = contact_get_property; object_class->set_property = contact_set_property; + g_object_class_install_property (object_class, + PROP_TP_CONTACT, + g_param_spec_object ("tp-contact", + "TpContact", + "The TpContact associated with the contact", + TP_TYPE_CONTACT, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, + PROP_ACCOUNT, + g_param_spec_object ("account", + "The account", + "The account associated with the contact", + MC_TYPE_ACCOUNT, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (object_class, PROP_ID, g_param_spec_string ("id", "Contact id", "String identifying contact", NULL, - G_PARAM_READWRITE)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_NAME, @@ -139,7 +170,7 @@ empathy_contact_class_init (EmpathyContactClass *class) "Contact Name", "The name of the contact", NULL, - G_PARAM_READWRITE)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_AVATAR, @@ -147,15 +178,7 @@ empathy_contact_class_init (EmpathyContactClass *class) "Avatar image", "The avatar image", EMPATHY_TYPE_AVATAR, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_ACCOUNT, - g_param_spec_object ("account", - "Contact Account", - "The account associated with the contact", - MC_TYPE_ACCOUNT, - G_PARAM_READWRITE)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_PRESENCE, @@ -165,7 +188,7 @@ empathy_contact_class_init (EmpathyContactClass *class) MC_PRESENCE_UNSET, LAST_MC_PRESENCE, MC_PRESENCE_UNSET, - G_PARAM_READWRITE)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_PRESENCE_MESSAGE, @@ -173,7 +196,7 @@ empathy_contact_class_init (EmpathyContactClass *class) "Contact presence message", "Presence message of contact", NULL, - G_PARAM_READWRITE)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_HANDLE, @@ -183,7 +206,7 @@ empathy_contact_class_init (EmpathyContactClass *class) 0, G_MAXUINT, 0, - G_PARAM_READWRITE)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_CAPABILITIES, @@ -192,7 +215,7 @@ empathy_contact_class_init (EmpathyContactClass *class) "Capabilities of the contact", EMPATHY_TYPE_CAPABILITIES, EMPATHY_CAPABILITIES_UNKNOWN, - G_PARAM_CONSTRUCT | G_PARAM_READWRITE)); + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_IS_USER, @@ -200,16 +223,7 @@ empathy_contact_class_init (EmpathyContactClass *class) "Contact is-user", "Is contact the user", FALSE, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_READY, - g_param_spec_flags ("ready", - "Contact ready flags", - "Flags for ready properties", - EMPATHY_TYPE_CONTACT_READY, - EMPATHY_CONTACT_READY_NONE, - G_PARAM_READABLE)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); signals[PRESENCE_CHANGED] = g_signal_new ("presence-changed", @@ -232,17 +246,12 @@ empathy_contact_init (EmpathyContact *contact) EMPATHY_TYPE_CONTACT, EmpathyContactPriv); contact->priv = priv; - - /* Keep a ref to the factory to be sure it is not finalized while there is - * still contacts alive. */ - priv->factory = empathy_contact_factory_dup_singleton (); } static void contact_finalize (GObject *object) { EmpathyContactPriv *priv; - GList *l; priv = GET_PRIV (object); @@ -252,66 +261,68 @@ contact_finalize (GObject *object) g_free (priv->id); g_free (priv->presence_message); - for (l = priv->ready_callbacks; l != NULL; l = g_list_next (l)) - { - ReadyCbData *d = (ReadyCbData *)l->data; - - if (d->destroy != NULL) - d->destroy (d->user_data); - g_slice_free (ReadyCbData, d); - } - - g_list_free (priv->ready_callbacks); - priv->ready_callbacks = NULL; - if (priv->avatar) empathy_avatar_unref (priv->avatar); G_OBJECT_CLASS (empathy_contact_parent_class)->finalize (object); } +static void +set_tp_contact (EmpathyContact *contact, + TpContact *tp_contact) +{ + EmpathyContactPriv *priv = GET_PRIV (contact); + + if (tp_contact == NULL) + return; + + g_assert (priv->tp_contact == NULL); + priv->tp_contact = g_object_ref (tp_contact); + priv->presence = empathy_contact_get_presence (contact); + + g_signal_connect (priv->tp_contact, "notify", + G_CALLBACK (tp_contact_notify_cb), contact); +} + static void contact_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec) { - EmpathyContactPriv *priv; - - priv = GET_PRIV (object); + EmpathyContact *contact = EMPATHY_CONTACT (object); switch (param_id) { + case PROP_TP_CONTACT: + g_value_set_object (value, empathy_contact_get_tp_contact (contact)); + break; + case PROP_ACCOUNT: + g_value_set_object (value, empathy_contact_get_account (contact)); + break; case PROP_ID: - g_value_set_string (value, priv->id); + g_value_set_string (value, empathy_contact_get_id (contact)); break; case PROP_NAME: - g_value_set_string (value, - empathy_contact_get_name (EMPATHY_CONTACT (object))); + g_value_set_string (value, empathy_contact_get_name (contact)); break; case PROP_AVATAR: - g_value_set_boxed (value, priv->avatar); - break; - case PROP_ACCOUNT: - g_value_set_object (value, priv->account); + g_value_set_boxed (value, empathy_contact_get_avatar (contact)); break; case PROP_PRESENCE: - g_value_set_uint (value, priv->presence); + g_value_set_uint (value, empathy_contact_get_presence (contact)); break; case PROP_PRESENCE_MESSAGE: - g_value_set_string (value, priv->presence_message); + g_value_set_string (value, empathy_contact_get_presence_message (contact)); break; case PROP_HANDLE: - g_value_set_uint (value, priv->handle); + g_value_set_uint (value, empathy_contact_get_handle (contact)); break; case PROP_CAPABILITIES: - g_value_set_flags (value, priv->capabilities); + g_value_set_flags (value, empathy_contact_get_capabilities (contact)); break; case PROP_IS_USER: - g_value_set_boolean (value, priv->is_user); - break; - case PROP_READY: - g_value_set_flags (value, priv->ready); + g_value_set_boolean (value, empathy_contact_is_user (contact)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -325,47 +336,41 @@ contact_set_property (GObject *object, const GValue *value, GParamSpec *pspec) { - EmpathyContactPriv *priv; - - priv = GET_PRIV (object); + EmpathyContact *contact = EMPATHY_CONTACT (object); + EmpathyContactPriv *priv = GET_PRIV (object); switch (param_id) { + case PROP_TP_CONTACT: + set_tp_contact (contact, g_value_get_object (value)); + break; + case PROP_ACCOUNT: + g_assert (priv->account == NULL); + priv->account = g_value_dup_object (value); + break; case PROP_ID: - empathy_contact_set_id (EMPATHY_CONTACT (object), - g_value_get_string (value)); + empathy_contact_set_id (contact, g_value_get_string (value)); break; case PROP_NAME: - empathy_contact_set_name (EMPATHY_CONTACT (object), - g_value_get_string (value)); + empathy_contact_set_name (contact, g_value_get_string (value)); break; case PROP_AVATAR: - empathy_contact_set_avatar (EMPATHY_CONTACT (object), - g_value_get_boxed (value)); - break; - case PROP_ACCOUNT: - empathy_contact_set_account (EMPATHY_CONTACT (object), - MC_ACCOUNT (g_value_get_object (value))); + empathy_contact_set_avatar (contact, g_value_get_boxed (value)); break; case PROP_PRESENCE: - empathy_contact_set_presence (EMPATHY_CONTACT (object), - g_value_get_uint (value)); + empathy_contact_set_presence (contact, g_value_get_uint (value)); break; case PROP_PRESENCE_MESSAGE: - empathy_contact_set_presence_message (EMPATHY_CONTACT (object), - g_value_get_string (value)); + empathy_contact_set_presence_message (contact, g_value_get_string (value)); break; case PROP_HANDLE: - empathy_contact_set_handle (EMPATHY_CONTACT (object), - g_value_get_uint (value)); + empathy_contact_set_handle (contact, g_value_get_uint (value)); break; case PROP_CAPABILITIES: - empathy_contact_set_capabilities (EMPATHY_CONTACT (object), - g_value_get_flags (value)); + empathy_contact_set_capabilities (contact, g_value_get_flags (value)); break; case PROP_IS_USER: - empathy_contact_set_is_user (EMPATHY_CONTACT (object), - g_value_get_boolean (value)); + empathy_contact_set_is_user (contact, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -373,120 +378,43 @@ contact_set_property (GObject *object, }; } -static gboolean -contact_is_ready (EmpathyContact *contact, EmpathyContactReady ready) -{ - EmpathyContactPriv *priv = GET_PRIV (contact); - - /* When the name is NULL, empathy_contact_get_name() fallback to the id. - * When the caller want to wait the name to be ready, it also want to wait - * the id to be ready in case of fallback. */ - if ((ready & EMPATHY_CONTACT_READY_NAME) && EMP_STR_EMPTY (priv->name)) - ready |= EMPATHY_CONTACT_READY_ID; - - return (priv->ready & ready) == ready; -} - -static void -contact_weak_object_notify (gpointer data, GObject *old_object) -{ - EmpathyContact *contact = EMPATHY_CONTACT (data); - EmpathyContactPriv *priv = GET_PRIV (contact); - - GList *l, *ln; - - for (l = priv->ready_callbacks ; l != NULL ; l = ln ) - { - ReadyCbData *d = (ReadyCbData *)l->data; - ln = g_list_next (l); - - if (d->weak_object == old_object) - { - if (d->destroy != NULL) - d->destroy (d->user_data); - - priv->ready_callbacks = g_list_delete_link (priv->ready_callbacks, - l); - - g_slice_free (ReadyCbData, d); - } - } -} - -static void -contact_call_ready_callback (EmpathyContact *contact, const GError *error, - ReadyCbData *data) -{ - data->callback (contact, error, data->user_data, data->weak_object); - if (data->destroy != NULL) - data->destroy (data->user_data); - - if (data->weak_object) - g_object_weak_unref (data->weak_object, - contact_weak_object_notify, contact); -} - - -static void -contact_set_ready_flag (EmpathyContact *contact, - EmpathyContactReady flag) -{ - EmpathyContactPriv *priv = GET_PRIV (contact); - - if (!(priv->ready & flag)) - { - GList *l, *ln; - - priv->ready |= flag; - g_object_notify (G_OBJECT (contact), "ready"); - - for (l = priv->ready_callbacks ; l != NULL ; l = ln ) - { - ReadyCbData *d = (ReadyCbData *)l->data; - ln = g_list_next (l); - - if (contact_is_ready (contact, d->ready)) - { - contact_call_ready_callback (contact, NULL, d); - priv->ready_callbacks = g_list_delete_link - (priv->ready_callbacks, l); - g_slice_free (ReadyCbData, d); - } - } - } -} - -static void -contact_remove_ready_flag (EmpathyContact *contact, - EmpathyContactReady flag) +EmpathyContact * +empathy_contact_new (TpContact *tp_contact) { - EmpathyContactPriv *priv = GET_PRIV (contact); + g_return_val_if_fail (TP_IS_CONTACT (tp_contact), NULL); - if (priv->ready & flag) - { - priv->ready ^= flag; - g_object_notify (G_OBJECT (contact), "ready"); - } + return g_object_new (EMPATHY_TYPE_CONTACT, + "tp-contact", tp_contact, + NULL); } EmpathyContact * -empathy_contact_new (McAccount *account) +empathy_contact_new_for_log (McAccount *account, + const gchar *id, + const gchar *name, + gboolean is_user) { + g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); + g_return_val_if_fail (id != NULL, NULL); + return g_object_new (EMPATHY_TYPE_CONTACT, "account", account, + "id", id, + "name", name, + "is-user", is_user, NULL); } -EmpathyContact * -empathy_contact_new_full (McAccount *account, - const gchar *id, - const gchar *name) +TpContact * +empathy_contact_get_tp_contact (EmpathyContact *contact) { - return g_object_new (EMPATHY_TYPE_CONTACT, - "account", account, - "name", name, - "id", id, - NULL); + EmpathyContactPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); + + priv = GET_PRIV (contact); + + return priv->tp_contact; } const gchar * @@ -498,6 +426,9 @@ empathy_contact_get_id (EmpathyContact *contact) priv = GET_PRIV (contact); + if (priv->tp_contact != NULL) + return tp_contact_get_identifier (priv->tp_contact); + return priv->id; } @@ -524,7 +455,6 @@ empathy_contact_set_id (EmpathyContact *contact, if (EMP_STR_EMPTY (priv->name)) g_object_notify (G_OBJECT (contact), "name"); } - contact_set_ready_flag (contact, EMPATHY_CONTACT_READY_ID); g_object_unref (contact); } @@ -538,6 +468,9 @@ empathy_contact_get_name (EmpathyContact *contact) priv = GET_PRIV (contact); + if (priv->tp_contact != NULL) + return tp_contact_get_alias (priv->tp_contact); + if (EMP_STR_EMPTY (priv->name)) return empathy_contact_get_id (contact); @@ -561,7 +494,6 @@ empathy_contact_set_name (EmpathyContact *contact, priv->name = g_strdup (name); g_object_notify (G_OBJECT (contact), "name"); } - contact_set_ready_flag (contact, EMPATHY_CONTACT_READY_NAME); g_object_unref (contact); } @@ -611,28 +543,61 @@ empathy_contact_get_account (EmpathyContact *contact) priv = GET_PRIV (contact); + if (priv->account == NULL && priv->tp_contact != NULL) + { + EmpathyAccountManager *manager; + TpConnection *connection; + + /* FIXME: This assume the account manager already exists */ + manager = empathy_account_manager_dup_singleton (); + connection = tp_contact_get_connection (priv->tp_contact); + priv->account = empathy_account_manager_get_account (manager, connection); + g_object_ref (priv->account); + g_object_unref (manager); + } + return priv->account; } -void -empathy_contact_set_account (EmpathyContact *contact, - McAccount *account) +TpConnection * +empathy_contact_get_connection (EmpathyContact *contact) { EmpathyContactPriv *priv; - g_return_if_fail (EMPATHY_IS_CONTACT (contact)); - g_return_if_fail (MC_IS_ACCOUNT (account)); + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); priv = GET_PRIV (contact); - if (account == priv->account) - return; + if (priv->tp_contact != NULL) + return tp_contact_get_connection (priv->tp_contact); - if (priv->account) - g_object_unref (priv->account); - priv->account = g_object_ref (account); + return NULL; +} + +static McPresence +presence_type_to_mc_presence (TpConnectionPresenceType type) +{ + switch (type) + { + case TP_CONNECTION_PRESENCE_TYPE_UNSET: + case TP_CONNECTION_PRESENCE_TYPE_UNKNOWN: + case TP_CONNECTION_PRESENCE_TYPE_ERROR: + return MC_PRESENCE_UNSET; + case TP_CONNECTION_PRESENCE_TYPE_OFFLINE: + return MC_PRESENCE_OFFLINE; + case TP_CONNECTION_PRESENCE_TYPE_AVAILABLE: + return MC_PRESENCE_AVAILABLE; + case TP_CONNECTION_PRESENCE_TYPE_AWAY: + return MC_PRESENCE_AWAY; + case TP_CONNECTION_PRESENCE_TYPE_EXTENDED_AWAY: + return MC_PRESENCE_EXTENDED_AWAY; + case TP_CONNECTION_PRESENCE_TYPE_HIDDEN: + return MC_PRESENCE_HIDDEN; + case TP_CONNECTION_PRESENCE_TYPE_BUSY: + return MC_PRESENCE_DO_NOT_DISTURB; + } - g_object_notify (G_OBJECT (contact), "account"); + return MC_PRESENCE_UNSET; } McPresence @@ -644,6 +609,10 @@ empathy_contact_get_presence (EmpathyContact *contact) priv = GET_PRIV (contact); + if (priv->tp_contact != NULL) + return presence_type_to_mc_presence (tp_contact_get_presence_type ( + priv->tp_contact)); + return priv->presence; } @@ -678,6 +647,9 @@ empathy_contact_get_presence_message (EmpathyContact *contact) priv = GET_PRIV (contact); + if (priv->tp_contact != NULL) + return tp_contact_get_presence_message (priv->tp_contact); + return priv->presence_message; } @@ -707,6 +679,9 @@ empathy_contact_get_handle (EmpathyContact *contact) priv = GET_PRIV (contact); + if (priv->tp_contact != NULL) + return tp_contact_get_handle (priv->tp_contact); + return priv->handle; } @@ -726,12 +701,6 @@ empathy_contact_set_handle (EmpathyContact *contact, priv->handle = handle; g_object_notify (G_OBJECT (contact), "handle"); } - - if (handle != 0) - contact_set_ready_flag (contact, EMPATHY_CONTACT_READY_HANDLE); - else - contact_remove_ready_flag (contact, EMPATHY_CONTACT_READY_HANDLE); - g_object_unref (contact); } @@ -798,28 +767,24 @@ empathy_contact_set_is_user (EmpathyContact *contact, gboolean empathy_contact_is_online (EmpathyContact *contact) { - EmpathyContactPriv *priv; - g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE); - priv = GET_PRIV (contact); - - return (priv->presence > MC_PRESENCE_OFFLINE); + return (empathy_contact_get_presence (contact) > MC_PRESENCE_OFFLINE); } const gchar * empathy_contact_get_status (EmpathyContact *contact) { - EmpathyContactPriv *priv; + const gchar *message; g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), ""); - priv = GET_PRIV (contact); - - if (priv->presence_message) - return priv->presence_message; + message = empathy_contact_get_presence_message (contact); + if (!EMP_STR_EMPTY (message)) + return message; - return empathy_presence_get_default_message (priv->presence); + return empathy_presence_get_default_message ( + empathy_contact_get_presence (contact)); } gboolean @@ -847,112 +812,12 @@ empathy_contact_can_send_files (EmpathyContact *contact) return priv->capabilities & EMPATHY_CAPABILITIES_FT; } -EmpathyContactReady -empathy_contact_get_ready (EmpathyContact *contact) -{ - EmpathyContactPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE); - - priv = GET_PRIV (contact); - - return priv->ready; -} - -gboolean -empathy_contact_equal (gconstpointer v1, - gconstpointer v2) -{ - McAccount *account_a; - McAccount *account_b; - const gchar *id_a; - const gchar *id_b; - - g_return_val_if_fail (EMPATHY_IS_CONTACT (v1), FALSE); - g_return_val_if_fail (EMPATHY_IS_CONTACT (v2), FALSE); - - account_a = empathy_contact_get_account (EMPATHY_CONTACT (v1)); - account_b = empathy_contact_get_account (EMPATHY_CONTACT (v2)); - - id_a = empathy_contact_get_id (EMPATHY_CONTACT (v1)); - id_b = empathy_contact_get_id (EMPATHY_CONTACT (v2)); - - return empathy_account_equal (account_a, account_b) && - !tp_strdiff (id_a, id_b); -} - -guint -empathy_contact_hash (gconstpointer key) -{ - EmpathyContactPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_CONTACT (key), +1); - - priv = GET_PRIV (EMPATHY_CONTACT (key)); - - if (priv->hash == 0) - { - priv->hash = empathy_account_hash (priv->account) ^ - g_str_hash (priv->id); - } - - return priv->hash; -} - -void empathy_contact_call_when_ready (EmpathyContact *contact, - EmpathyContactReady ready, EmpathyContactReadyCb *callback, - gpointer user_data, GDestroyNotify destroy, GObject *weak_object) -{ - EmpathyContactPriv *priv = GET_PRIV (contact); - - g_return_if_fail (contact != NULL); - g_return_if_fail (callback != NULL); - - if (contact_is_ready (contact, ready)) - { - callback (contact, NULL, user_data, weak_object); - if (destroy != NULL) - destroy (user_data); - } - else - { - ReadyCbData *d = g_slice_new0 (ReadyCbData); - d->ready = ready; - d->callback = callback; - d->user_data = user_data; - d->destroy = destroy; - d->weak_object = weak_object; - - if (weak_object != NULL) - g_object_weak_ref (weak_object, contact_weak_object_notify, contact); - - priv->ready_callbacks = g_list_prepend (priv->ready_callbacks, d); - } -} - -static gboolean -contact_is_ready_func (GObject *contact, - gpointer user_data) -{ - return contact_is_ready (EMPATHY_CONTACT (contact), - GPOINTER_TO_UINT (user_data)); -} - -void -empathy_contact_run_until_ready (EmpathyContact *contact, - EmpathyContactReady ready, - GMainLoop **loop) -{ - empathy_run_until_ready_full (contact, "notify::ready", - contact_is_ready_func, GUINT_TO_POINTER (ready), - loop); -} - static gchar * contact_get_avatar_filename (EmpathyContact *contact, const gchar *token) { EmpathyContactPriv *priv = GET_PRIV (contact); + McAccount *account; gchar *avatar_path; gchar *avatar_file; gchar *token_escaped; @@ -963,11 +828,13 @@ contact_get_avatar_filename (EmpathyContact *contact, contact_escaped = tp_escape_as_identifier (priv->id); token_escaped = tp_escape_as_identifier (token); + account = empathy_contact_get_account (contact); + /* FIXME: Do not use the account, but proto/cm instead */ avatar_path = g_build_filename (g_get_user_cache_dir (), PACKAGE_NAME, "avatars", - mc_account_get_unique_name (priv->account), + mc_account_get_unique_name (account), contact_escaped, NULL); g_mkdir_with_parents (avatar_path, 0700); diff --git a/libempathy/empathy-contact.h b/libempathy/empathy-contact.h index 52c969f6..c10561d0 100644 --- a/libempathy/empathy-contact.h +++ b/libempathy/empathy-contact.h @@ -1,26 +1,22 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * Copyright (C) 2004 Imendio AB - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. + * This library 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.1 of the License, or (at your option) any later version. * - * This program is distributed in the hope that it will be useful, + * This library 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 - * General Public License for more details. + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * - * Authors: Mikael Hallendal - * Martyn Russell - * Xavier Claessens + * Authors: Xavier Claessens */ #ifndef __EMPATHY_CONTACT_H__ @@ -28,8 +24,8 @@ #include +#include #include -#include G_BEGIN_DECLS @@ -70,18 +66,11 @@ typedef enum { EMPATHY_CAPABILITIES_UNKNOWN = 1 << 7 } EmpathyCapabilities; -typedef enum { - EMPATHY_CONTACT_READY_NONE = 0, - EMPATHY_CONTACT_READY_ID = 1 << 0, - EMPATHY_CONTACT_READY_HANDLE = 1 << 1, - EMPATHY_CONTACT_READY_NAME = 1 << 2, - EMPATHY_CONTACT_READY_ALL = (1 << 3) - 1, -} EmpathyContactReady; - GType empathy_contact_get_type (void) G_GNUC_CONST; -EmpathyContact * empathy_contact_new (McAccount *account); -EmpathyContact * empathy_contact_new_full (McAccount *account, const gchar *id, - const gchar *name); +EmpathyContact * empathy_contact_new (TpContact *tp_contact); +EmpathyContact * empathy_contact_new_for_log (McAccount *account, + const gchar *id, const gchar *name, gboolean is_user); +TpContact * empathy_contact_get_tp_contact (EmpathyContact *contact); const gchar * empathy_contact_get_id (EmpathyContact *contact); void empathy_contact_set_id (EmpathyContact *contact, const gchar *id); const gchar * empathy_contact_get_name (EmpathyContact *contact); @@ -90,7 +79,7 @@ EmpathyAvatar * empathy_contact_get_avatar (EmpathyContact *contact); void empathy_contact_set_avatar (EmpathyContact *contact, EmpathyAvatar *avatar); McAccount * empathy_contact_get_account (EmpathyContact *contact); -void empathy_contact_set_account (EmpathyContact *contact, McAccount *account); +TpConnection * empathy_contact_get_connection (EmpathyContact *contact); McPresence empathy_contact_get_presence (EmpathyContact *contact); void empathy_contact_set_presence (EmpathyContact *contact, McPresence presence); @@ -102,7 +91,6 @@ void empathy_contact_set_handle (EmpathyContact *contact, guint handle); EmpathyCapabilities empathy_contact_get_capabilities (EmpathyContact *contact); void empathy_contact_set_capabilities (EmpathyContact *contact, EmpathyCapabilities capabilities); -EmpathyContactReady empathy_contact_get_ready (EmpathyContact *contact); gboolean empathy_contact_is_user (EmpathyContact *contact); void empathy_contact_set_is_user (EmpathyContact *contact, gboolean is_user); @@ -110,19 +98,8 @@ gboolean empathy_contact_is_online (EmpathyContact *contact); const gchar * empathy_contact_get_status (EmpathyContact *contact); gboolean empathy_contact_can_voip (EmpathyContact *contact); gboolean empathy_contact_can_send_files (EmpathyContact *contact); -gboolean empathy_contact_equal (gconstpointer v1, gconstpointer v2); guint empathy_contact_hash (gconstpointer key); -typedef void (EmpathyContactReadyCb) - (EmpathyContact *contact, const GError *error, gpointer user_data, - GObject *weak_object); -void empathy_contact_call_when_ready (EmpathyContact *contact, - EmpathyContactReady ready, EmpathyContactReadyCb *callback, gpointer - user_data, GDestroyNotify destroy, GObject *weak_object); - -void empathy_contact_run_until_ready (EmpathyContact *contact, - EmpathyContactReady ready, GMainLoop **loop); - void empathy_contact_load_avatar_data (EmpathyContact *contact, const guchar *data, const gsize len, const gchar *format, const gchar *token); diff --git a/libempathy/empathy-dispatch-operation.c b/libempathy/empathy-dispatch-operation.c index 1786e416..cfe11118 100644 --- a/libempathy/empathy-dispatch-operation.c +++ b/libempathy/empathy-dispatch-operation.c @@ -24,6 +24,7 @@ #include "empathy-dispatch-operation.h" #include +#include #include #include #include @@ -172,11 +173,38 @@ empathy_dispatch_operation_invalidated (TpProxy *proxy, guint domain, g_signal_emit (self, signals[INVALIDATED], 0, domain, code, message); } +static void +dispatcher_operation_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *self) +{ + EmpathyDispatchOperationPriv *priv = GET_PRIV (self); + + if (error) + { + /* FIXME: We should cancel the operation */ + DEBUG ("Error: %s", error->message); + return; + } + + if (priv->contact != NULL) + g_object_unref (priv->contact); + priv->contact = g_object_ref (contact); + g_object_notify (G_OBJECT (self), "contact"); + + tp_channel_call_when_ready (priv->channel, + empathy_dispatch_operation_channel_ready_cb, self); +} + static void empathy_dispatch_operation_constructed (GObject *object) { EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (object); EmpathyDispatchOperationPriv *priv = GET_PRIV (self); + TpHandle handle; + TpHandleType handle_type; empathy_dispatch_operation_set_status (self, EMPATHY_DISPATCHER_OPERATION_STATE_PREPARING); @@ -185,6 +213,19 @@ empathy_dispatch_operation_constructed (GObject *object) g_signal_connect (priv->channel, "invalidated", G_CALLBACK (empathy_dispatch_operation_invalidated), self); + handle = tp_channel_get_handle (priv->channel, &handle_type); + + if (handle_type == TP_CONN_HANDLE_TYPE_CONTACT && priv->contact == NULL) + { + EmpathyTpContactFactory *factory; + + factory = empathy_tp_contact_factory_dup_singleton (priv->connection); + empathy_tp_contact_factory_get_from_handle (factory, handle, + dispatcher_operation_got_contact_cb, NULL, NULL, object); + g_object_unref (factory); + return; + } + tp_channel_call_when_ready (priv->channel, empathy_dispatch_operation_channel_ready_cb, self); } @@ -364,6 +405,23 @@ empathy_dispatcher_operation_tp_chat_ready_cb (GObject *object, EMPATHY_DISPATCHER_OPERATION_STATE_PENDING); } +static void +empathy_dispatcher_operation_tp_file_ready_cb (GObject *object, + GParamSpec *spec, gpointer user_data) +{ + EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (user_data); + EmpathyDispatchOperationPriv *priv = GET_PRIV (self); + + if (!empathy_tp_file_is_ready (EMPATHY_TP_FILE (priv->channel_wrapper))) + return; + + g_signal_handler_disconnect (priv->channel_wrapper, priv->ready_handler); + priv->ready_handler = 0; + + empathy_dispatch_operation_set_status (self, + EMPATHY_DISPATCHER_OPERATION_STATE_PENDING); +} + static void empathy_dispatch_operation_channel_ready_cb (TpChannel *channel, const GError *error, gpointer user_data) @@ -395,18 +453,23 @@ empathy_dispatch_operation_channel_ready_cb (TpChannel *channel, G_CALLBACK (empathy_dispatcher_operation_tp_chat_ready_cb), self); return; } - } else if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_STREAMED_MEDIA) { - EmpathyTpCall *call = empathy_tp_call_new (channel); - priv->channel_wrapper = G_OBJECT (call); - + EmpathyTpCall *call = empathy_tp_call_new (channel); + priv->channel_wrapper = G_OBJECT (call); } else if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_FILE_TRANSFER) { - EmpathyTpFile *file = empathy_tp_file_new (channel); - priv->channel_wrapper = G_OBJECT (file); + EmpathyTpFile *file = empathy_tp_file_new (channel); + priv->channel_wrapper = G_OBJECT (file); + + if (!empathy_tp_file_is_ready (file)) + { + priv->ready_handler = g_signal_connect (file, "notify::ready", + G_CALLBACK (empathy_dispatcher_operation_tp_file_ready_cb), self); + return; + } } ready: @@ -524,7 +587,7 @@ empathy_dispatch_operation_get_tp_connection ( priv = GET_PRIV (operation); - return g_object_ref (priv->connection); + return priv->connection; } TpChannel * diff --git a/libempathy/empathy-dispatcher.c b/libempathy/empathy-dispatcher.c index 12c7da96..c8a0f9e6 100644 --- a/libempathy/empathy-dispatcher.c +++ b/libempathy/empathy-dispatcher.c @@ -31,7 +31,6 @@ #include #include -#include #include @@ -39,7 +38,7 @@ #include "empathy-utils.h" #include "empathy-tube-handler.h" #include "empathy-account-manager.h" -#include "empathy-contact-factory.h" +#include "empathy-tp-contact-factory.h" #include "empathy-tp-file.h" #include "empathy-chatroom-manager.h" #include "empathy-utils.h" @@ -54,8 +53,6 @@ typedef struct MissionControl *mc; /* connection to connection data mapping */ GHashTable *connections; - /* accounts to connection mapping */ - GHashTable *accounts; gpointer token; GSList *tubes; @@ -102,7 +99,6 @@ typedef struct typedef struct { - McAccount *account; /* ObjectPath => DispatchData.. */ GHashTable *dispatched_channels; /* ObjectPath -> EmpathyDispatchOperations */ @@ -185,10 +181,9 @@ free_dispatcher_request_data (DispatcherRequestData *r) } static ConnectionData * -new_connection_data (McAccount *account) +new_connection_data (void) { ConnectionData *cd = g_slice_new0 (ConnectionData); - cd->account = g_object_ref (account); cd->dispatched_channels = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) free_dispatch_data); @@ -206,7 +201,7 @@ static void free_connection_data (ConnectionData *cd) { GList *l; - g_object_unref (cd->account); + g_hash_table_destroy (cd->dispatched_channels); g_hash_table_destroy (cd->dispatching_channels); int i; @@ -233,12 +228,8 @@ dispatcher_connection_invalidated_cb (TpConnection *connection, EmpathyDispatcher *dispatcher) { EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); - ConnectionData *cd; DEBUG ("Error: %s", message); - cd = g_hash_table_lookup (priv->connections, connection); - - g_hash_table_remove (priv->accounts, cd->account); g_hash_table_remove (priv->connections, connection); } @@ -362,7 +353,6 @@ dispatch_operation_claimed_cb (EmpathyDispatchOperation *operation, connection = empathy_dispatch_operation_get_tp_connection (operation); cd = g_hash_table_lookup (priv->connections, connection); g_assert (cd != NULL); - g_object_unref (G_OBJECT (connection)); object_path = empathy_dispatch_operation_get_object_path (operation); @@ -406,7 +396,6 @@ dispatch_operation_ready_cb (EmpathyDispatchOperation *operation, connection = empathy_dispatch_operation_get_tp_connection (operation); cd = g_hash_table_lookup (priv->connections, connection); g_assert (cd != NULL); - g_object_unref (G_OBJECT (connection)); g_object_ref (operation); g_object_ref (dispatcher); @@ -511,7 +500,6 @@ dispatcher_connection_new_channel (EmpathyDispatcher *dispatcher, TpChannel *channel; ConnectionData *cd; EmpathyDispatchOperation *operation; - EmpathyContact *contact = NULL; int i; /* Channel types we never want to dispatch because they're either deprecated * or can't sensibly be dispatch (e.g. channels that should always be @@ -575,15 +563,7 @@ dispatcher_connection_new_channel (EmpathyDispatcher *dispatcher, priv->channels = g_list_prepend (priv->channels, channel); - if (handle_type == TP_CONN_HANDLE_TYPE_CONTACT) - { - EmpathyContactFactory *factory = empathy_contact_factory_dup_singleton (); - contact = empathy_contact_factory_get_from_handle (factory, - cd->account, handle); - g_object_unref (factory); - } - - operation = empathy_dispatch_operation_new (connection, channel, contact, + operation = empathy_dispatch_operation_new (connection, channel, NULL, incoming); g_object_unref (channel); @@ -786,21 +766,21 @@ dispatcher_connection_advertise_capabilities_cb (TpConnection *connection, } static void -dispatcher_connection_ready_cb (TpConnection *connection, - const GError *error, - gpointer dispatcher) +dispatcher_new_connection_cb (EmpathyAccountManager *manager, + TpConnection *connection, + EmpathyDispatcher *dispatcher) { + EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); GPtrArray *capabilities; GType cap_type; GValue cap = {0, }; const gchar *remove = NULL; - if (error) - { - dispatcher_connection_invalidated_cb (connection, error->domain, - error->code, error->message, dispatcher); - return; - } + if (g_hash_table_lookup (priv->connections, connection) != NULL) + return; + + g_hash_table_insert (priv->connections, g_object_ref (connection), + new_connection_data ()); g_signal_connect (connection, "invalidated", G_CALLBACK (dispatcher_connection_invalidated_cb), dispatcher); @@ -815,7 +795,7 @@ dispatcher_connection_ready_cb (TpConnection *connection, tp_cli_dbus_properties_call_get_all (connection, -1, TP_IFACE_CONNECTION_INTERFACE_REQUESTS, dispatcher_connection_got_all, - NULL, NULL, dispatcher); + NULL, NULL, G_OBJECT (dispatcher)); } else { @@ -852,44 +832,6 @@ dispatcher_connection_ready_cb (TpConnection *connection, g_ptr_array_free (capabilities, TRUE); } -static void -dispatcher_update_account (EmpathyDispatcher *dispatcher, - McAccount *account) -{ - EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); - TpConnection *connection; - - connection = g_hash_table_lookup (priv->accounts, account); - if (connection != NULL) - return; - - connection = mission_control_get_tpconnection (priv->mc, account, NULL); - if (connection == NULL) - return; - - g_hash_table_insert (priv->connections, g_object_ref (connection), - new_connection_data (account)); - - g_hash_table_insert (priv->accounts, g_object_ref (account), - g_object_ref (connection)); - - tp_connection_call_when_ready (connection, dispatcher_connection_ready_cb, - dispatcher); - - g_object_unref (connection); -} - -static void -dispatcher_account_connection_cb (EmpathyAccountManager *manager, - McAccount *account, - TpConnectionStatusReason reason, - TpConnectionStatus status, - TpConnectionStatus previous, - EmpathyDispatcher *dispatcher) -{ - dispatcher_update_account (dispatcher, account); -} - static GObject* dispatcher_constructor (GType type, guint n_construct_params, @@ -922,7 +864,7 @@ dispatcher_finalize (GObject *object) gpointer connection; g_signal_handlers_disconnect_by_func (priv->account_manager, - dispatcher_account_connection_cb, object); + dispatcher_new_connection_cb, object); for (l = priv->channels; l; l = l->next) { @@ -942,7 +884,6 @@ dispatcher_finalize (GObject *object) g_object_unref (priv->account_manager); g_object_unref (priv->mc); - g_hash_table_destroy (priv->accounts); g_hash_table_destroy (priv->connections); } @@ -991,7 +932,7 @@ empathy_dispatcher_class_init (EmpathyDispatcherClass *klass) static void empathy_dispatcher_init (EmpathyDispatcher *dispatcher) { - GList *accounts, *l; + GList *connections, *l; EmpathyDispatcherPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (dispatcher, EMPATHY_TYPE_DISPATCHER, EmpathyDispatcherPriv); @@ -999,27 +940,22 @@ empathy_dispatcher_init (EmpathyDispatcher *dispatcher) priv->mc = empathy_mission_control_dup_singleton (); priv->account_manager = empathy_account_manager_dup_singleton (); - g_signal_connect (priv->account_manager, - "account-connection-changed", - G_CALLBACK (dispatcher_account_connection_cb), + g_signal_connect (priv->account_manager, "new-connection", + G_CALLBACK (dispatcher_new_connection_cb), dispatcher); - priv->accounts = g_hash_table_new_full (empathy_account_hash, - empathy_account_equal, g_object_unref, g_object_unref); - priv->connections = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, (GDestroyNotify) free_connection_data); priv->channels = NULL; - accounts = mc_accounts_list_by_enabled (TRUE); - - for (l = accounts; l; l = l->next) + connections = empathy_account_manager_dup_connections (priv->account_manager); + for (l = connections; l; l = l->next) { - dispatcher_update_account (dispatcher, l->data); + dispatcher_new_connection_cb (priv->account_manager, l->data, dispatcher); g_object_unref (l->data); } - g_list_free (accounts); + g_list_free (connections); } EmpathyDispatcher * @@ -1167,50 +1103,6 @@ dispatcher_request_channel (DispatcherRequestData *request_data) request_data, NULL, G_OBJECT (request_data->dispatcher)); } -void -empathy_dispatcher_call_with_contact (EmpathyContact *contact, - EmpathyDispatcherRequestCb *callback, - gpointer user_data) -{ - EmpathyDispatcher *dispatcher = empathy_dispatcher_dup_singleton(); - EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); - McAccount *account; - TpConnection *connection; - ConnectionData *cd; - DispatcherRequestData *request_data; - - g_return_if_fail (EMPATHY_IS_CONTACT (contact)); - - account = empathy_contact_get_account (contact); - connection = g_hash_table_lookup (priv->accounts, account); - - g_assert (connection != NULL); - cd = g_hash_table_lookup (priv->connections, connection); - request_data = new_dispatcher_request_data (dispatcher, connection, - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, TP_HANDLE_TYPE_NONE, 0, NULL, - contact, callback, user_data); - - cd->outstanding_requests = g_list_prepend - (cd->outstanding_requests, request_data); - - dispatcher_request_channel (request_data); - - g_object_unref (dispatcher); -} - -static void -dispatcher_chat_with_contact_cb (EmpathyContact *contact, - const GError *error, - gpointer user_data, - GObject *object) -{ - DispatcherRequestData *request_data = (DispatcherRequestData *) user_data; - - request_data->handle = empathy_contact_get_handle (contact); - - dispatcher_request_channel (request_data); -} - void empathy_dispatcher_chat_with_contact (EmpathyContact *contact, EmpathyDispatcherRequestCb *callback, @@ -1218,7 +1110,6 @@ empathy_dispatcher_chat_with_contact (EmpathyContact *contact, { EmpathyDispatcher *dispatcher; EmpathyDispatcherPriv *priv; - McAccount *account; TpConnection *connection; ConnectionData *connection_data; DispatcherRequestData *request_data; @@ -1228,46 +1119,75 @@ empathy_dispatcher_chat_with_contact (EmpathyContact *contact, dispatcher = empathy_dispatcher_dup_singleton(); priv = GET_PRIV (dispatcher); - account = empathy_contact_get_account (contact); - connection = g_hash_table_lookup (priv->accounts, account); + connection = empathy_contact_get_connection (contact); connection_data = g_hash_table_lookup (priv->connections, connection); /* The contact handle might not be known yet */ request_data = new_dispatcher_request_data (dispatcher, connection, - TP_IFACE_CHANNEL_TYPE_TEXT, TP_HANDLE_TYPE_CONTACT, 0, NULL, - contact, callback, user_data); + TP_IFACE_CHANNEL_TYPE_TEXT, TP_HANDLE_TYPE_CONTACT, + empathy_contact_get_handle (contact), NULL, contact, callback, user_data); connection_data->outstanding_requests = g_list_prepend (connection_data->outstanding_requests, request_data); - empathy_contact_call_when_ready (contact, - EMPATHY_CONTACT_READY_HANDLE, dispatcher_chat_with_contact_cb, - request_data, NULL, G_OBJECT (dispatcher)); + dispatcher_request_channel (request_data); g_object_unref (dispatcher); } +typedef struct +{ + EmpathyDispatcher *dispatcher; + EmpathyDispatcherRequestCb *callback; + gpointer user_data; +} ChatWithContactIdData; + +static void +dispatcher_chat_with_contact_id_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + ChatWithContactIdData *data = user_data; + + if (error) + { + /* FIXME: Should call data->callback with the error */ + DEBUG ("Error: %s", error->message); + } + else + { + empathy_dispatcher_chat_with_contact (contact, data->callback, data->user_data); + } + + g_object_unref (data->dispatcher); + g_slice_free (ChatWithContactIdData, data); +} + void -empathy_dispatcher_chat_with_contact_id (McAccount *account, +empathy_dispatcher_chat_with_contact_id (TpConnection *connection, const gchar *contact_id, EmpathyDispatcherRequestCb *callback, gpointer user_data) { - EmpathyDispatcher *dispatcher = empathy_dispatcher_dup_singleton (); - EmpathyContactFactory *factory; - EmpathyContact *contact; + EmpathyDispatcher *dispatcher; + EmpathyTpContactFactory *factory; + ChatWithContactIdData *data; - g_return_if_fail (MC_IS_ACCOUNT (account)); + g_return_if_fail (TP_IS_CONNECTION (connection)); g_return_if_fail (!EMP_STR_EMPTY (contact_id)); - factory = empathy_contact_factory_dup_singleton (); - contact = empathy_contact_factory_get_from_id (factory, account, contact_id); - - empathy_dispatcher_chat_with_contact (contact, callback, user_data); + dispatcher = empathy_dispatcher_dup_singleton (); + factory = empathy_tp_contact_factory_dup_singleton (connection); + data = g_slice_new0 (ChatWithContactIdData); + data->dispatcher = dispatcher; + data->callback = callback; + data->user_data = user_data; + empathy_tp_contact_factory_get_from_id (factory, contact_id, + dispatcher_chat_with_contact_id_cb, data, NULL, NULL); - g_object_unref (contact); g_object_unref (factory); - g_object_unref (dispatcher); } static void @@ -1304,7 +1224,7 @@ dispatcher_request_handles_cb (TpConnection *connection, } void -empathy_dispatcher_join_muc (McAccount *account, +empathy_dispatcher_join_muc (TpConnection *connection, const gchar *roomname, EmpathyDispatcherRequestCb *callback, gpointer user_data) @@ -1312,20 +1232,17 @@ empathy_dispatcher_join_muc (McAccount *account, EmpathyDispatcher *dispatcher; EmpathyDispatcherPriv *priv; DispatcherRequestData *request_data; - TpConnection *connection; ConnectionData *connection_data; const gchar *names[] = { roomname, NULL }; - g_return_if_fail (MC_IS_ACCOUNT (account)); + g_return_if_fail (TP_IS_CONNECTION (connection)); g_return_if_fail (!EMP_STR_EMPTY (roomname)); dispatcher = empathy_dispatcher_dup_singleton(); priv = GET_PRIV (dispatcher); - connection = g_hash_table_lookup (priv->accounts, account); connection_data = g_hash_table_lookup (priv->connections, connection); - /* Don't know the room handle yet */ request_data = new_dispatcher_request_data (dispatcher, connection, TP_IFACE_CHANNEL_TYPE_TEXT, TP_HANDLE_TYPE_ROOM, 0, NULL, @@ -1359,7 +1276,7 @@ dispatcher_create_channel_cb (TpConnection *connect, void empathy_dispatcher_create_channel (EmpathyDispatcher *dispatcher, - McAccount *account, + TpConnection *connection, GHashTable *request, EmpathyDispatcherRequestCb *callback, gpointer user_data) @@ -1371,15 +1288,11 @@ empathy_dispatcher_create_channel (EmpathyDispatcher *dispatcher, guint handle_type; guint handle; gboolean valid; - TpConnection *connection; g_return_if_fail (EMPATHY_IS_DISPATCHER (dispatcher)); - g_return_if_fail (MC_IS_ACCOUNT (account)); + g_return_if_fail (TP_IS_CONNECTION (connection)); g_return_if_fail (request != NULL); - connection = g_hash_table_lookup (priv->accounts, account); - g_assert (connection != NULL); - connection_data = g_hash_table_lookup (priv->connections, connection); g_assert (connection_data != NULL); @@ -1405,56 +1318,6 @@ empathy_dispatcher_create_channel (EmpathyDispatcher *dispatcher, G_OBJECT (request_data->dispatcher)); } -static void -dispatcher_create_channel_with_contact_cb (EmpathyContact *contact, - const GError *error, - gpointer user_data, - GObject *object) -{ - DispatcherRequestData *request_data = (DispatcherRequestData *) user_data; - GValue *target_handle; - - g_assert (request_data->request); - - if (error != NULL) - { - dispatcher_request_failed (request_data->dispatcher, - request_data, error); - return; - } - - request_data->handle = empathy_contact_get_handle (contact); - - target_handle = tp_g_value_slice_new (G_TYPE_UINT); - g_value_set_uint (target_handle, request_data->handle); - g_hash_table_insert (request_data->request, - TP_IFACE_CHANNEL ".TargetHandle", target_handle); - - tp_cli_connection_interface_requests_call_create_channel ( - request_data->connection, -1, - request_data->request, dispatcher_create_channel_cb, request_data, NULL, - G_OBJECT (request_data->dispatcher)); -} - -static void -dispatcher_send_file_connection_ready_cb (TpConnection *connection, - const GError *error, - gpointer user_data) -{ - DispatcherRequestData *request_data = (DispatcherRequestData *) user_data; - - if (error != NULL) - { - dispatcher_request_failed (request_data->dispatcher, - request_data, error); - return; - } - - empathy_contact_call_when_ready (request_data->contact, - EMPATHY_CONTACT_READY_HANDLE, dispatcher_create_channel_with_contact_cb, - request_data, NULL, G_OBJECT (request_data->dispatcher)); -} - void empathy_dispatcher_send_file_to_contact (EmpathyContact *contact, const gchar *filename, @@ -1466,8 +1329,7 @@ empathy_dispatcher_send_file_to_contact (EmpathyContact *contact, { EmpathyDispatcher *dispatcher = empathy_dispatcher_dup_singleton(); EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); - McAccount *account = empathy_contact_get_account (contact); - TpConnection *connection = g_hash_table_lookup (priv->accounts, account); + TpConnection *connection = empathy_contact_get_connection (contact); ConnectionData *connection_data = g_hash_table_lookup (priv->connections, connection); DispatcherRequestData *request_data; @@ -1489,6 +1351,11 @@ empathy_dispatcher_send_file_to_contact (EmpathyContact *contact, g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT); g_hash_table_insert (request, TP_IFACE_CHANNEL ".TargetHandleType", value); + /* org.freedesktop.Telepathy.Channel.TargetHandle */ + value = tp_g_value_slice_new (G_TYPE_UINT); + g_value_set_uint (value, empathy_contact_get_handle (contact)); + g_hash_table_insert (request, TP_IFACE_CHANNEL ".TargetHandle", value); + /* org.freedesktop.Telepathy.Channel.Type.FileTransfer.ContentType */ value = tp_g_value_slice_new (G_TYPE_STRING); g_value_set_string (value, content_type); @@ -1513,46 +1380,40 @@ empathy_dispatcher_send_file_to_contact (EmpathyContact *contact, g_hash_table_insert (request, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".Date", value); - - /* The contact handle might not be known yet */ - request_data = new_dispatcher_request_data (dispatcher, connection, - TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, TP_HANDLE_TYPE_CONTACT, 0, request, - contact, callback, user_data); + request_data = new_dispatcher_request_data (dispatcher, connection, + TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, TP_HANDLE_TYPE_CONTACT, + empathy_contact_get_handle (contact), request, contact, callback, + user_data); connection_data->outstanding_requests = g_list_prepend (connection_data->outstanding_requests, request_data); - tp_connection_call_when_ready (connection, - dispatcher_send_file_connection_ready_cb, (gpointer) request_data); + tp_cli_connection_interface_requests_call_create_channel ( + request_data->connection, -1, + request_data->request, dispatcher_create_channel_cb, request_data, NULL, + G_OBJECT (request_data->dispatcher)); g_object_unref (dispatcher); } GStrv empathy_dispatcher_find_channel_class (EmpathyDispatcher *dispatcher, - McAccount *account, + TpConnection *connection, const gchar *channel_type, guint handle_type) { EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); ConnectionData *cd; - TpConnection *connection; int i; GPtrArray *classes; g_return_val_if_fail (channel_type != NULL, NULL); g_return_val_if_fail (handle_type != 0, NULL); - connection = g_hash_table_lookup (priv->accounts, account); - - if (connection == NULL) - return NULL; - cd = g_hash_table_lookup (priv->connections, connection); if (cd == NULL) return NULL; - classes = cd->requestable_channels; if (classes == NULL) return NULL; diff --git a/libempathy/empathy-dispatcher.h b/libempathy/empathy-dispatcher.h index 13ef06af..fb7c6fe3 100644 --- a/libempathy/empathy-dispatcher.h +++ b/libempathy/empathy-dispatcher.h @@ -62,15 +62,11 @@ typedef void (EmpathyDispatcherRequestCb) ( GType empathy_dispatcher_get_type (void) G_GNUC_CONST; void empathy_dispatcher_create_channel (EmpathyDispatcher *dispatcher, - McAccount *account, GHashTable *request, - EmpathyDispatcherRequestCb *callback, gpointer user_data); - -/* Requesting 1 to 1 stream media channels */ -void empathy_dispatcher_call_with_contact (EmpathyContact *contact, + TpConnection *connection, GHashTable *request, EmpathyDispatcherRequestCb *callback, gpointer user_data); /* Requesting 1 to 1 text channels */ -void empathy_dispatcher_chat_with_contact_id (McAccount *account, +void empathy_dispatcher_chat_with_contact_id (TpConnection *connection, const gchar *contact_id, EmpathyDispatcherRequestCb *callback, gpointer user_data); void empathy_dispatcher_chat_with_contact (EmpathyContact *contact, @@ -83,12 +79,12 @@ void empathy_dispatcher_send_file_to_contact (EmpathyContact *contact, gpointer user_data); /* Request a muc channel */ -void empathy_dispatcher_join_muc (McAccount *account, +void empathy_dispatcher_join_muc (TpConnection *connection, const gchar *roomname, EmpathyDispatcherRequestCb *callback, gpointer user_data); GStrv empathy_dispatcher_find_channel_class (EmpathyDispatcher *dispatcher, - McAccount *account, const gchar *channel_type, guint handle_type); + TpConnection *connection, const gchar *channel_type, guint handle_type); /* Get the dispatcher singleton */ EmpathyDispatcher * empathy_dispatcher_dup_singleton (void); diff --git a/libempathy/empathy-log-store-empathy.c b/libempathy/empathy-log-store-empathy.c index 37a76676..b74b5e17 100644 --- a/libempathy/empathy-log-store-empathy.c +++ b/libempathy/empathy-log-store-empathy.c @@ -481,8 +481,9 @@ log_store_empathy_get_messages_for_file (EmpathyLogStore *self, t = empathy_time_parse (time); - sender = empathy_contact_new_full (account, sender_id, sender_name); - empathy_contact_set_is_user (sender, is_user); + sender = empathy_contact_new_for_log (account, sender_id, sender_name, + is_user); + if (!EMP_STR_EMPTY (sender_avatar_token)) empathy_contact_load_avatar_cache (sender, sender_avatar_token); diff --git a/libempathy/empathy-tp-call.c b/libempathy/empathy-tp-call.c index 42bf7a06..a5c0003c 100644 --- a/libempathy/empathy-tp-call.c +++ b/libempathy/empathy-tp-call.c @@ -27,7 +27,7 @@ #include #include "empathy-tp-call.h" -#include "empathy-contact-factory.h" +#include "empathy-tp-contact-factory.h" #include "empathy-utils.h" #define DEBUG_FLAG EMPATHY_DEBUG_TP @@ -253,22 +253,27 @@ tp_call_request_streams_for_capabilities (EmpathyTpCall *call, g_array_free (stream_types, TRUE); } -static EmpathyContact * -tp_call_dup_contact_from_handle (EmpathyTpCall *call, TpHandle handle) +static void +tp_call_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *call) { EmpathyTpCallPriv *priv = GET_PRIV (call); - EmpathyContactFactory *factory; - McAccount *account; - EmpathyContact *contact; - - factory = empathy_contact_factory_dup_singleton (); - account = empathy_channel_get_account (priv->channel); - contact = empathy_contact_factory_get_from_handle (factory, account, handle); - g_object_unref (factory); - g_object_unref (account); + if (error) + { + DEBUG ("Error: %s", error->message); + return; + } - return contact; + priv->contact = g_object_ref (contact); + priv->is_incoming = TRUE; + priv->status = EMPATHY_TP_CALL_STATUS_PENDING; + g_object_notify (G_OBJECT (call), "is-incoming"); + g_object_notify (G_OBJECT (call), "contact"); + g_object_notify (G_OBJECT (call), "status"); } static void @@ -288,13 +293,15 @@ tp_call_update_status (EmpathyTpCall *call) { if (priv->contact == NULL && iter.element != self_handle) { + EmpathyTpContactFactory *factory; + TpConnection *connection; + /* We found the remote contact */ - priv->contact = tp_call_dup_contact_from_handle (call, iter.element); - priv->is_incoming = TRUE; - priv->status = EMPATHY_TP_CALL_STATUS_PENDING; - g_object_notify (G_OBJECT (call), "is-incoming"); - g_object_notify (G_OBJECT (call), "contact"); - g_object_notify (G_OBJECT (call), "status"); + connection = tp_channel_borrow_connection (priv->channel); + factory = empathy_tp_contact_factory_dup_singleton (connection); + empathy_tp_contact_factory_get_from_handle (factory, iter.element, + tp_call_got_contact_cb, NULL, NULL, G_OBJECT (call)); + g_object_unref (factory); } if (priv->status == EMPATHY_TP_CALL_STATUS_PENDING && @@ -309,20 +316,6 @@ tp_call_update_status (EmpathyTpCall *call) g_object_unref (call); } -static void -tp_call_members_changed_cb (TpChannel *channel, - gchar *message, - GArray *added, - GArray *removed, - GArray *local_pending, - GArray *remote_pending, - guint actor, - guint reason, - EmpathyTpCall *call) -{ - tp_call_update_status (call); -} - void empathy_tp_call_to (EmpathyTpCall *call, EmpathyContact *contact) { @@ -392,8 +385,8 @@ tp_call_constructor (GType type, /* Update status when members changes */ tp_call_update_status (call); - g_signal_connect (priv->channel, "group-members-changed", - G_CALLBACK (tp_call_members_changed_cb), call); + g_signal_connect_swapped (priv->channel, "group-members-changed", + G_CALLBACK (tp_call_update_status), call); return object; } diff --git a/libempathy/empathy-tp-chat.c b/libempathy/empathy-tp-chat.c index 048f5b27..54e08d07 100644 --- a/libempathy/empathy-tp-chat.c +++ b/libempathy/empathy-tp-chat.c @@ -28,8 +28,7 @@ #include #include "empathy-tp-chat.h" -#include "empathy-tp-group.h" -#include "empathy-contact-factory.h" +#include "empathy-tp-contact-factory.h" #include "empathy-contact-monitor.h" #include "empathy-contact-list.h" #include "empathy-marshal.h" @@ -42,12 +41,11 @@ #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyTpChat) typedef struct { gboolean dispose_has_run; - EmpathyContactFactory *factory; + EmpathyTpContactFactory *factory; EmpathyContactMonitor *contact_monitor; EmpathyContact *user; EmpathyContact *remote_contact; - EmpathyTpGroup *group; - McAccount *account; + GList *members; TpChannel *channel; gboolean listing_pending_messages; /* Queue of messages not signalled yet */ @@ -57,7 +55,6 @@ typedef struct { gboolean had_properties_list; GPtrArray *properties; gboolean ready; - guint members_count; } EmpathyTpChatPriv; typedef struct { @@ -100,13 +97,8 @@ tp_chat_invalidated_cb (TpProxy *proxy, gchar *message, EmpathyTpChat *chat) { - EmpathyTpChatPriv *priv = GET_PRIV (chat); - DEBUG ("Channel invalidated: %s", message); g_signal_emit (chat, signals[DESTROY], 0); - - g_object_unref (priv->channel); - priv->channel = NULL; } static void @@ -120,108 +112,6 @@ tp_chat_async_cb (TpChannel *proxy, } } -static void -tp_chat_member_added_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpChat *chat) -{ - EmpathyTpChatPriv *priv = GET_PRIV (chat); - guint handle_type = 0; - - if (priv->channel == NULL) - return; - - priv->members_count++; - g_signal_emit_by_name (chat, "members-changed", - contact, actor, reason, message, - TRUE); - - g_object_get (priv->channel, "handle-type", &handle_type, NULL); - if (handle_type == TP_HANDLE_TYPE_ROOM) { - return; - } - - if (priv->members_count > 2 && priv->remote_contact) { - /* We now have more than 2 members, this is not a p2p chat - * anymore. Remove the remote-contact as it makes no sense, the - * EmpathyContactList interface must be used now. */ - g_object_unref (priv->remote_contact); - priv->remote_contact = NULL; - g_object_notify (G_OBJECT (chat), "remote-contact"); - } - if (priv->members_count <= 2 && !priv->remote_contact && - !empathy_contact_is_user (contact)) { - /* This is a p2p chat, if it's not ourself that means this is - * the remote contact with who we are chatting. This is to - * avoid forcing the usage of the EmpathyContactList interface - * for p2p chats. */ - priv->remote_contact = g_object_ref (contact); - g_object_notify (G_OBJECT (chat), "remote-contact"); - } -} - -static void -tp_chat_member_removed_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpChat *chat) -{ - EmpathyTpChatPriv *priv = GET_PRIV (chat); - guint handle_type = 0; - - if (priv->channel == NULL) - return; - - priv->members_count--; - g_signal_emit_by_name (chat, "members-changed", - contact, actor, reason, message, - FALSE); - - g_object_get (priv->channel, "handle-type", &handle_type, NULL); - if (handle_type == TP_HANDLE_TYPE_ROOM) { - return; - } - - if (priv->members_count <= 2 && !priv->remote_contact) { - GList *members, *l; - - /* We are not a MUC anymore, get the remote contact back */ - members = empathy_tp_group_get_members (group); - for (l = members; l; l = l->next) { - if (!empathy_contact_is_user (l->data)) { - priv->remote_contact = g_object_ref (l->data); - g_object_notify (G_OBJECT (chat), "remote-contact"); - break; - } - } - g_list_foreach (members, (GFunc) g_object_unref, NULL); - g_list_free (members); - } -} - -static void -tp_chat_local_pending_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpChat *chat) -{ - EmpathyTpChatPriv *priv = GET_PRIV (chat); - - if (priv->channel == NULL) - return; - - g_signal_emit_by_name (chat, "pendings-changed", - contact, actor, reason, message, - TRUE); -} - static void tp_chat_add (EmpathyContactList *list, EmpathyContact *contact, @@ -268,8 +158,9 @@ tp_chat_get_members (EmpathyContactList *list) g_return_val_if_fail (EMPATHY_IS_TP_CHAT (list), NULL); - if (priv->group) { - members = empathy_tp_group_get_members (priv->group); + if (priv->members) { + members = g_list_copy (priv->members); + g_list_foreach (members, (GFunc) g_object_ref, NULL); } else { members = g_list_prepend (members, g_object_ref (priv->user)); members = g_list_prepend (members, g_object_ref (priv->remote_contact)); @@ -294,119 +185,74 @@ tp_chat_get_monitor (EmpathyContactList *list) return priv->contact_monitor; } -static EmpathyMessage * -tp_chat_build_message (EmpathyTpChat *chat, - guint id, - guint type, - guint timestamp, - guint from_handle, - const gchar *message_body) +static void +tp_chat_emit_queued_messages (EmpathyTpChat *chat) { - EmpathyTpChatPriv *priv; + EmpathyTpChatPriv *priv = GET_PRIV (chat); EmpathyMessage *message; - EmpathyContact *sender; - priv = GET_PRIV (chat); - - if (from_handle == 0) { - sender = g_object_ref (priv->user); - } else { - sender = empathy_contact_factory_get_from_handle (priv->factory, - priv->account, - from_handle); - } - - message = empathy_message_new (message_body); - empathy_message_set_tptype (message, type); - empathy_message_set_sender (message, sender); - empathy_message_set_receiver (message, priv->user); - empathy_message_set_timestamp (message, timestamp); - empathy_message_set_id (message, id); - - g_object_unref (sender); - - return message; -} - -static void -tp_chat_sender_ready_notify_cb (EmpathyContact *contact, - GParamSpec *param_spec, - EmpathyTpChat *chat) -{ - EmpathyTpChatPriv *priv = GET_PRIV (chat); - EmpathyMessage *message; - EmpathyContactReady ready; - EmpathyContact *sender = NULL; - gboolean removed = FALSE; - - /* Emit all messages queued until we find a message with not - * ready sender (in case of a MUC we could have more than one sender). - * When leaving this loop, sender is the first not ready contact queued - * and removed tells if at least one message got removed - * from the queue. */ + /* Check if we can now emit some queued messages */ while ((message = g_queue_peek_head (priv->messages_queue)) != NULL) { - sender = empathy_message_get_sender (message); - ready = empathy_contact_get_ready (sender); - - if ((ready & EMPATHY_CONTACT_READY_NAME) == 0 || - (ready & EMPATHY_CONTACT_READY_ID) == 0) { + if (empathy_message_get_sender (message) == NULL) { break; } DEBUG ("Queued message ready"); - message = g_queue_pop_head (priv->messages_queue); + g_queue_pop_head (priv->messages_queue); g_queue_push_tail (priv->pending_messages_queue, message); g_signal_emit (chat, signals[MESSAGE_RECEIVED], 0, message); - removed = TRUE; } +} - if (removed) { - /* We removed at least one message from the queue, disconnect - * the ready signal from the previous contact */ - g_signal_handlers_disconnect_by_func (contact, - tp_chat_sender_ready_notify_cb, - chat); - - if (g_queue_get_length (priv->messages_queue) > 0) { - /* We still have queued message, connect the ready - * signal on the new first message sender. */ - g_signal_connect (sender, "notify::ready", - G_CALLBACK (tp_chat_sender_ready_notify_cb), - chat); - } +static void +tp_chat_got_sender_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer message, + GObject *chat) +{ + EmpathyTpChatPriv *priv = GET_PRIV (chat); + + if (error) { + DEBUG ("Error: %s", error->message); + /* Do not block the message queue, just drop this message */ + g_queue_remove (priv->messages_queue, message); + } else { + empathy_message_set_sender (message, contact); } + + tp_chat_emit_queued_messages (EMPATHY_TP_CHAT (chat)); } static void -tp_chat_emit_or_queue_message (EmpathyTpChat *chat, - EmpathyMessage *message) +tp_chat_build_message (EmpathyTpChat *chat, + guint id, + guint type, + guint timestamp, + guint from_handle, + const gchar *message_body) { - EmpathyTpChatPriv *priv = GET_PRIV (chat); - EmpathyContact *sender; - EmpathyContactReady ready; + EmpathyTpChatPriv *priv; + EmpathyMessage *message; - if (g_queue_get_length (priv->messages_queue) > 0) { - DEBUG ("Message queue not empty"); - g_queue_push_tail (priv->messages_queue, g_object_ref (message)); - return; - } + priv = GET_PRIV (chat); + message = empathy_message_new (message_body); + empathy_message_set_tptype (message, type); + empathy_message_set_receiver (message, priv->user); + empathy_message_set_timestamp (message, timestamp); + empathy_message_set_id (message, id); + g_queue_push_tail (priv->messages_queue, message); - sender = empathy_message_get_sender (message); - ready = empathy_contact_get_ready (sender); - if ((ready & EMPATHY_CONTACT_READY_NAME) && - (ready & EMPATHY_CONTACT_READY_ID)) { - DEBUG ("Message queue empty and sender ready"); - g_queue_push_tail (priv->pending_messages_queue, g_object_ref (message)); - g_signal_emit (chat, signals[MESSAGE_RECEIVED], 0, message); - return; + if (from_handle == 0) { + empathy_message_set_sender (message, priv->user); + tp_chat_emit_queued_messages (chat); + } else { + empathy_tp_contact_factory_get_from_handle (priv->factory, + from_handle, + tp_chat_got_sender_cb, + message, NULL, G_OBJECT (chat)); } - - DEBUG ("Sender not ready"); - g_queue_push_tail (priv->messages_queue, g_object_ref (message)); - g_signal_connect (sender, "notify::ready", - G_CALLBACK (tp_chat_sender_ready_notify_cb), - chat); } static void @@ -422,7 +268,6 @@ tp_chat_received_cb (TpChannel *channel, { EmpathyTpChat *chat = EMPATHY_TP_CHAT (chat_); EmpathyTpChatPriv *priv = GET_PRIV (chat); - EmpathyMessage *message; if (priv->channel == NULL) return; @@ -447,15 +292,12 @@ tp_chat_received_cb (TpChannel *channel, return; } - message = tp_chat_build_message (chat, - message_id, - message_type, - timestamp, - from_handle, - message_body); - - tp_chat_emit_or_queue_message (chat, message); - g_object_unref (message); + tp_chat_build_message (chat, + message_id, + message_type, + timestamp, + from_handle, + message_body); } static void @@ -468,22 +310,18 @@ tp_chat_sent_cb (TpChannel *channel, { EmpathyTpChat *chat = EMPATHY_TP_CHAT (chat_); EmpathyTpChatPriv *priv = GET_PRIV (chat); - EmpathyMessage *message; if (priv->channel == NULL) return; DEBUG ("Message sent: %s", message_body); - message = tp_chat_build_message (chat, - 0, - message_type, - timestamp, - 0, - message_body); - - tp_chat_emit_or_queue_message (chat, message); - g_object_unref (message); + tp_chat_build_message (chat, + 0, + message_type, + timestamp, + 0, + message_body); } static void @@ -495,7 +333,6 @@ tp_chat_send_error_cb (TpChannel *channel, gpointer user_data, GObject *chat) { - EmpathyMessage *message; EmpathyTpChatPriv *priv = GET_PRIV (chat); if (priv->channel == NULL) @@ -503,15 +340,12 @@ tp_chat_send_error_cb (TpChannel *channel, DEBUG ("Message sent error: %s (%d)", message_body, error_code); - message = tp_chat_build_message (EMPATHY_TP_CHAT (chat), - 0, - message_type, - timestamp, - 0, - message_body); - - g_signal_emit (chat, signals[SEND_ERROR], 0, message, error_code); - g_object_unref (message); + tp_chat_build_message (EMPATHY_TP_CHAT (chat), + 0, + message_type, + timestamp, + 0, + message_body); } static void @@ -529,28 +363,45 @@ tp_chat_send_cb (TpChannel *proxy, } } +typedef struct { + EmpathyTpChat *chat; + TpChannelChatState state; +} StateChangedData; + static void -tp_chat_state_changed_cb (TpChannel *channel, - guint handle, - guint state, - gpointer user_data, - GObject *chat) +tp_chat_state_changed_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *chat) { - EmpathyTpChatPriv *priv = GET_PRIV (chat); - EmpathyContact *contact; + TpChannelChatState state; - if (priv->channel == NULL) + if (error) { + DEBUG ("Error: %s", error->message); return; + } - contact = empathy_contact_factory_get_from_handle (priv->factory, - priv->account, - handle); - + state = GPOINTER_TO_UINT (user_data); DEBUG ("Chat state changed for %s (%d): %d", - empathy_contact_get_name (contact), handle, state); + empathy_contact_get_name (contact), + empathy_contact_get_handle (contact), state); g_signal_emit (chat, signals[CHAT_STATE_CHANGED], 0, contact, state); - g_object_unref (contact); +} + +static void +tp_chat_state_changed_cb (TpChannel *channel, + TpHandle handle, + TpChannelChatState state, + gpointer user_data, + GObject *chat) +{ + EmpathyTpChatPriv *priv = GET_PRIV (chat); + + empathy_tp_contact_factory_get_from_handle (priv->factory, handle, + tp_chat_state_changed_got_contact_cb, GUINT_TO_POINTER (state), + NULL, chat); } static void @@ -576,7 +427,6 @@ tp_chat_list_pending_messages_cb (TpChannel *channel, } for (i = 0; i < messages_list->len; i++) { - EmpathyMessage *message; GValueArray *message_struct; const gchar *message_body; guint message_id; @@ -608,15 +458,12 @@ tp_chat_list_pending_messages_cb (TpChannel *channel, continue; } - message = tp_chat_build_message (chat, - message_id, - message_type, - timestamp, - from_handle, - message_body); - - tp_chat_emit_or_queue_message (chat, message); - g_object_unref (message); + tp_chat_build_message (chat, + message_id, + message_type, + timestamp, + from_handle, + message_body); } if (empty_non_text_content_ids != NULL) { @@ -781,8 +628,6 @@ empathy_tp_chat_set_property (EmpathyTpChat *chat, TpChatProperty *property; guint i; - g_return_if_fail (priv->ready); - for (i = 0; i < priv->properties->len; i++) { property = g_ptr_array_index (priv->properties, i); if (!tp_strdiff (property->name, name)) { @@ -824,64 +669,90 @@ empathy_tp_chat_set_property (EmpathyTpChat *chat, } static void -tp_chat_channel_ready_cb (EmpathyTpChat *chat) +tp_chat_dispose (GObject *object) { - EmpathyTpChatPriv *priv = GET_PRIV (chat); - TpConnection *connection; - guint handle, handle_type; + EmpathyTpChat *self = EMPATHY_TP_CHAT (object); + EmpathyTpChatPriv *priv = GET_PRIV (self); - if (priv->channel == NULL) + if (priv->dispose_has_run) return; - DEBUG ("Channel ready"); - - g_object_get (priv->channel, - "connection", &connection, - "handle", &handle, - "handle_type", &handle_type, - NULL); + priv->dispose_has_run = TRUE; - if (handle_type == TP_HANDLE_TYPE_CONTACT && handle != 0) { - priv->remote_contact = empathy_contact_factory_get_from_handle (priv->factory, - priv->account, - handle); - g_object_notify (G_OBJECT (chat), "remote-contact"); + if (priv->channel != NULL) { + g_signal_handlers_disconnect_by_func (priv->channel, + tp_chat_invalidated_cb, self); + g_object_unref (priv->channel); } + priv->channel = NULL; - if (tp_proxy_has_interface_by_id (priv->channel, - TP_IFACE_QUARK_CHANNEL_INTERFACE_GROUP)) { - priv->group = empathy_tp_group_new (priv->channel); - - g_signal_connect (priv->group, "member-added", - G_CALLBACK (tp_chat_member_added_cb), - chat); - g_signal_connect (priv->group, "member-removed", - G_CALLBACK (tp_chat_member_removed_cb), - chat); - g_signal_connect (priv->group, "local-pending", - G_CALLBACK (tp_chat_local_pending_cb), - chat); - empathy_run_until_ready (priv->group); - } else { - priv->members_count = 2; + if (priv->remote_contact != NULL) + g_object_unref (priv->remote_contact); + priv->remote_contact = NULL; + + if (priv->factory != NULL) + g_object_unref (priv->factory); + priv->factory = NULL; + + if (priv->user != NULL); + g_object_unref (priv->user); + priv->user = NULL; + + if (priv->contact_monitor) + g_object_unref (priv->contact_monitor); + priv->contact_monitor = NULL; + + g_queue_foreach (priv->messages_queue, (GFunc) g_object_unref, NULL); + g_queue_clear (priv->messages_queue); + + g_queue_foreach (priv->pending_messages_queue, + (GFunc) g_object_unref, NULL); + g_queue_clear (priv->pending_messages_queue); + + if (G_OBJECT_CLASS (empathy_tp_chat_parent_class)->dispose) + G_OBJECT_CLASS (empathy_tp_chat_parent_class)->dispose (object); +} + +static void +tp_chat_finalize (GObject *object) +{ + EmpathyTpChatPriv *priv = GET_PRIV (object); + guint i; + + DEBUG ("Finalize: %p", object); + + if (priv->properties) { + for (i = 0; i < priv->properties->len; i++) { + TpChatProperty *property; + + property = g_ptr_array_index (priv->properties, i); + g_free (property->name); + if (property->value) { + tp_g_value_slice_free (property->value); + } + g_slice_free (TpChatProperty, property); + } + g_ptr_array_free (priv->properties, TRUE); } - - if (tp_proxy_has_interface_by_id (priv->channel, - TP_IFACE_QUARK_PROPERTIES_INTERFACE)) { - tp_cli_properties_interface_call_list_properties (priv->channel, -1, - tp_chat_list_properties_cb, - NULL, NULL, - G_OBJECT (chat)); - tp_cli_properties_interface_connect_to_properties_changed (priv->channel, - tp_chat_properties_changed_cb, - NULL, NULL, - G_OBJECT (chat), NULL); - tp_cli_properties_interface_connect_to_property_flags_changed (priv->channel, - tp_chat_property_flags_changed_cb, - NULL, NULL, - G_OBJECT (chat), NULL); + + g_queue_free (priv->messages_queue); + g_queue_free (priv->pending_messages_queue); + + G_OBJECT_CLASS (empathy_tp_chat_parent_class)->finalize (object); +} + +static void +tp_chat_check_if_ready (EmpathyTpChat *chat) +{ + EmpathyTpChatPriv *priv = GET_PRIV (chat); + + if (priv->ready || priv->user == NULL || + (priv->members == NULL && priv->remote_contact == NULL)) { + return; } + DEBUG ("Ready!"); + priv->listing_pending_messages = TRUE; tp_cli_channel_type_text_call_list_pending_messages (priv->channel, -1, FALSE, @@ -909,101 +780,184 @@ tp_chat_channel_ready_cb (EmpathyTpChat *chat) tp_chat_state_changed_cb, NULL, NULL, G_OBJECT (chat), NULL); - priv->ready = TRUE; g_object_notify (G_OBJECT (chat), "ready"); } static void -tp_chat_dispose (GObject *object) +tp_chat_update_remote_contact (EmpathyTpChat *chat) { - EmpathyTpChat *self = EMPATHY_TP_CHAT (object); - EmpathyTpChatPriv *priv = GET_PRIV (self); + EmpathyTpChatPriv *priv = GET_PRIV (chat); + EmpathyContact *contact = NULL; + TpHandle self_handle; + TpHandleType handle_type; + GList *l; - if (priv->dispose_has_run) + /* If this is a named chatroom, never pretend it is a private chat */ + tp_channel_get_handle (priv->channel, &handle_type); + if (handle_type == TP_HANDLE_TYPE_ROOM) { return; + } - priv->dispose_has_run = TRUE; - - if (priv->channel != NULL) - { - g_signal_handlers_disconnect_by_func (priv->channel, - tp_chat_invalidated_cb, self); - g_object_unref (priv->channel); - priv->channel = NULL; + /* This is an MSN-like chat where anyone can join the chat at anytime. + * If there is only one non-self contact member, we are in a private + * chat and we set the "remote-contact" property to that contact. If + * there are more, set the "remote-contact" property to NULL and the + * UI will display a contact list. */ + self_handle = tp_channel_group_get_self_handle (priv->channel); + for (l = priv->members; l; l = l->next) { + /* Skip self contact if member */ + if (empathy_contact_get_handle (l->data) == self_handle) { + continue; } - if (priv->remote_contact != NULL) - g_object_unref (priv->remote_contact); + /* We have more than one remote contact, break */ + if (contact != NULL) { + contact = NULL; + break; + } - priv->remote_contact = NULL; + /* If we didn't find yet a remote contact, keep this one */ + contact = l->data; + } - if (priv->group != NULL) - g_object_unref (priv->group); - priv->group = NULL; + if (priv->remote_contact == contact) { + return; + } - if (priv->factory != NULL) - g_object_unref (priv->factory); - priv->factory = NULL; + DEBUG ("Changing remote contact from %p to %p", + priv->remote_contact, contact); - if (priv->user != NULL); - g_object_unref (priv->user); - priv->user = NULL; + if (priv->remote_contact) { + g_object_unref (priv->remote_contact); + } - if (priv->account != NULL); - g_object_unref (priv->account); - priv->account = NULL; + priv->remote_contact = contact ? g_object_ref (contact) : NULL; + g_object_notify (G_OBJECT (chat), "remote-contact"); +} - if (priv->contact_monitor) - g_object_unref (priv->contact_monitor); - priv->contact_monitor = NULL; +static void +tp_chat_got_added_contacts_cb (EmpathyTpContactFactory *factory, + guint n_contacts, + EmpathyContact * const * contacts, + guint n_failed, + const TpHandle *failed, + const GError *error, + gpointer user_data, + GObject *chat) +{ + EmpathyTpChatPriv *priv = GET_PRIV (chat); + guint i; + const TpIntSet *members; + TpHandle handle; + EmpathyContact *contact; - if (!g_queue_is_empty (priv->messages_queue)) { - EmpathyMessage *message; - EmpathyContact *contact; + if (error) { + DEBUG ("Error: %s", error->message); + return; + } - message = g_queue_peek_head (priv->messages_queue); - contact = empathy_message_get_sender (message); - g_signal_handlers_disconnect_by_func (contact, - tp_chat_sender_ready_notify_cb, object); + members = tp_channel_group_get_members (priv->channel); + for (i = 0; i < n_contacts; i++) { + contact = contacts[i]; + handle = empathy_contact_get_handle (contact); + + /* Make sure the contact is still member */ + if (tp_intset_is_member (members, handle)) { + priv->members = g_list_prepend (priv->members, + g_object_ref (contact)); + g_signal_emit_by_name (chat, "members-changed", + contact, NULL, 0, NULL, FALSE); + } } - g_list_foreach (priv->messages_queue->head, - (GFunc) g_object_unref, NULL); + tp_chat_update_remote_contact (EMPATHY_TP_CHAT (chat)); + tp_chat_check_if_ready (EMPATHY_TP_CHAT (chat)); +} - g_list_foreach (priv->pending_messages_queue->head, - (GFunc) g_object_unref, NULL); +static void +tp_chat_group_members_changed_cb (TpChannel *self, + gchar *message, + GArray *added, + GArray *removed, + GArray *local_pending, + GArray *remote_pending, + guint actor, + guint reason, + EmpathyTpChat *chat) +{ + EmpathyTpChatPriv *priv = GET_PRIV (chat); + EmpathyContact *contact; + TpHandle handle; + guint i; + GList *l; - if (G_OBJECT_CLASS (empathy_tp_chat_parent_class)->dispose) - G_OBJECT_CLASS (empathy_tp_chat_parent_class)->dispose (object); + /* Remove contacts that are not members anymore */ + for (i = 0; i < removed->len; i++) { + for (l = priv->members; l; l = l->next) { + contact = l->data; + handle = empathy_contact_get_handle (contact); + if (handle == g_array_index (removed, TpHandle, i)) { + priv->members = g_list_delete_link (priv->members, l); + g_signal_emit_by_name (chat, "members-changed", + contact, NULL, reason, + message, FALSE); + g_object_unref (contact); + break; + } + } + } + + /* Request added contacts */ + if (added->len > 0) { + empathy_tp_contact_factory_get_from_handles (priv->factory, + added->len, (TpHandle*) added->data, + tp_chat_got_added_contacts_cb, NULL, NULL, + G_OBJECT (chat)); + } + + tp_chat_update_remote_contact (chat); } static void -tp_chat_finalize (GObject *object) +tp_chat_got_remote_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *chat) { - EmpathyTpChatPriv *priv = GET_PRIV (object); - guint i; + EmpathyTpChatPriv *priv = GET_PRIV (chat); - DEBUG ("Finalize: %p", object); + if (error) { + DEBUG ("Error: %s", error->message); + empathy_tp_chat_close (EMPATHY_TP_CHAT (chat)); + return; + } - if (priv->properties) { - for (i = 0; i < priv->properties->len; i++) { - TpChatProperty *property; + priv->remote_contact = g_object_ref (contact); + g_object_notify (chat, "remote-contact"); - property = g_ptr_array_index (priv->properties, i); - g_free (property->name); - if (property->value) { - tp_g_value_slice_free (property->value); - } - g_slice_free (TpChatProperty, property); - } - g_ptr_array_free (priv->properties, TRUE); - } + tp_chat_check_if_ready (EMPATHY_TP_CHAT (chat)); +} - g_queue_free (priv->messages_queue); - g_queue_free (priv->pending_messages_queue); +static void +tp_chat_got_self_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *chat) +{ + EmpathyTpChatPriv *priv = GET_PRIV (chat); - G_OBJECT_CLASS (empathy_tp_chat_parent_class)->finalize (object); + if (error) { + DEBUG ("Error: %s", error->message); + empathy_tp_chat_close (EMPATHY_TP_CHAT (chat)); + return; + } + + priv->user = g_object_ref (contact); + empathy_contact_set_is_user (priv->user, TRUE); + tp_chat_check_if_ready (EMPATHY_TP_CHAT (chat)); } static GObject * @@ -1013,26 +967,67 @@ tp_chat_constructor (GType type, { GObject *chat; EmpathyTpChatPriv *priv; - gboolean channel_ready; + TpConnection *connection; + TpHandle handle; chat = G_OBJECT_CLASS (empathy_tp_chat_parent_class)->constructor (type, n_props, props); priv = GET_PRIV (chat); - priv->account = empathy_channel_get_account (priv->channel); - priv->factory = empathy_contact_factory_dup_singleton (); - priv->user = empathy_contact_factory_get_user (priv->factory, priv->account); + connection = tp_channel_borrow_connection (priv->channel); + priv->factory = empathy_tp_contact_factory_dup_singleton (connection); g_signal_connect (priv->channel, "invalidated", G_CALLBACK (tp_chat_invalidated_cb), chat); - g_object_get (priv->channel, "channel-ready", &channel_ready, NULL); - if (channel_ready) { - tp_chat_channel_ready_cb (EMPATHY_TP_CHAT (chat)); + if (tp_proxy_has_interface_by_id (priv->channel, + TP_IFACE_QUARK_CHANNEL_INTERFACE_GROUP)) { + const TpIntSet *members; + GArray *handles; + + /* Get self contact from the group's self handle */ + handle = tp_channel_group_get_self_handle (priv->channel); + empathy_tp_contact_factory_get_from_handle (priv->factory, + handle, tp_chat_got_self_contact_cb, + NULL, NULL, chat); + + /* Get initial member contacts */ + members = tp_channel_group_get_members (priv->channel); + handles = tp_intset_to_array (members); + empathy_tp_contact_factory_get_from_handles (priv->factory, + handles->len, (TpHandle*) handles->data, + tp_chat_got_added_contacts_cb, NULL, NULL, chat); + + g_signal_connect (priv->channel, "group-members-changed", + G_CALLBACK (tp_chat_group_members_changed_cb), chat); } else { - g_signal_connect_swapped (priv->channel, "notify::channel-ready", - G_CALLBACK (tp_chat_channel_ready_cb), - chat); + /* Get the self contact from the connection's self handle */ + handle = tp_connection_get_self_handle (connection); + empathy_tp_contact_factory_get_from_handle (priv->factory, + handle, tp_chat_got_self_contact_cb, + NULL, NULL, chat); + + /* Get the remote contact */ + handle = tp_channel_get_handle (priv->channel, NULL); + empathy_tp_contact_factory_get_from_handle (priv->factory, + handle, tp_chat_got_remote_contact_cb, + NULL, NULL, chat); + } + + if (tp_proxy_has_interface_by_id (priv->channel, + TP_IFACE_QUARK_PROPERTIES_INTERFACE)) { + tp_cli_properties_interface_call_list_properties (priv->channel, -1, + tp_chat_list_properties_cb, + NULL, NULL, + G_OBJECT (chat)); + tp_cli_properties_interface_connect_to_properties_changed (priv->channel, + tp_chat_properties_changed_cb, + NULL, NULL, + G_OBJECT (chat), NULL); + tp_cli_properties_interface_connect_to_property_flags_changed (priv->channel, + tp_chat_property_flags_changed_cb, + NULL, NULL, + G_OBJECT (chat), NULL); } return chat; @@ -1107,6 +1102,7 @@ empathy_tp_chat_class_init (EmpathyTpChatClass *klass) "The remote contact if there is no group iface on the channel", EMPATHY_TYPE_CONTACT, G_PARAM_READABLE)); + g_object_class_install_property (object_class, PROP_READY, g_param_spec_boolean ("ready", @@ -1203,17 +1199,9 @@ empathy_tp_chat_close (EmpathyTpChat *chat) { EmpathyTpChatPriv *priv = GET_PRIV (chat); /* If there are still messages left, it'll come back.. - We loose the ordering of sent messages though */ - g_signal_handlers_disconnect_by_func (priv->channel, - tp_chat_invalidated_cb, chat); - + * We loose the ordering of sent messages though */ tp_cli_channel_call_close (priv->channel, -1, tp_chat_async_cb, "closing channel", NULL, NULL); - - g_object_unref (priv->channel); - priv->channel = NULL; - - g_signal_emit (chat, signals[DESTROY], 0); } const gchar * @@ -1222,7 +1210,6 @@ empathy_tp_chat_get_id (EmpathyTpChat *chat) EmpathyTpChatPriv *priv = GET_PRIV (chat); g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL); - g_return_val_if_fail (priv->ready, NULL); return tp_channel_get_identifier (priv->channel); } @@ -1233,28 +1220,29 @@ empathy_tp_chat_get_remote_contact (EmpathyTpChat *chat) EmpathyTpChatPriv *priv = GET_PRIV (chat); g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL); + g_return_val_if_fail (priv->ready, NULL); return priv->remote_contact; } -McAccount * -empathy_tp_chat_get_account (EmpathyTpChat *chat) +TpChannel * +empathy_tp_chat_get_channel (EmpathyTpChat *chat) { EmpathyTpChatPriv *priv = GET_PRIV (chat); - g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), FALSE); + g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL); - return priv->account; + return priv->channel; } -TpChannel * -empathy_tp_chat_get_channel (EmpathyTpChat *chat) +TpConnection * +empathy_tp_chat_get_connection (EmpathyTpChat *chat) { EmpathyTpChatPriv *priv = GET_PRIV (chat); g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL); - return priv->channel; + return tp_channel_borrow_connection (priv->channel); } gboolean @@ -1267,16 +1255,6 @@ empathy_tp_chat_is_ready (EmpathyTpChat *chat) return priv->ready; } -guint -empathy_tp_chat_get_members_count (EmpathyTpChat *chat) -{ - EmpathyTpChatPriv *priv = GET_PRIV (chat); - - g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), 0); - - return priv->members_count; -} - void empathy_tp_chat_send (EmpathyTpChat *chat, EmpathyMessage *message) @@ -1326,6 +1304,9 @@ empathy_tp_chat_get_pending_messages (EmpathyTpChat *chat) { EmpathyTpChatPriv *priv = GET_PRIV (chat); + g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL); + g_return_val_if_fail (priv->ready, NULL); + return priv->pending_messages_queue->head; } @@ -1346,6 +1327,9 @@ empathy_tp_chat_acknowledge_message (EmpathyTpChat *chat, GList *m; guint id; + g_return_if_fail (EMPATHY_IS_TP_CHAT (chat)); + g_return_if_fail (priv->ready); + if (empathy_message_get_sender (message) == priv->user) goto out; @@ -1373,6 +1357,9 @@ empathy_tp_chat_acknowledge_messages (EmpathyTpChat *chat, guint length; GArray *message_ids; + g_return_if_fail (EMPATHY_IS_TP_CHAT (chat)); + g_return_if_fail (priv->ready); + length = g_list_length ((GList *)messages); if (length == 0) @@ -1402,3 +1389,4 @@ empathy_tp_chat_acknowledge_messages (EmpathyTpChat *chat, g_array_free (message_ids, TRUE); g_list_free (msgs); } + diff --git a/libempathy/empathy-tp-chat.h b/libempathy/empathy-tp-chat.h index 35305292..fadc5f63 100644 --- a/libempathy/empathy-tp-chat.h +++ b/libempathy/empathy-tp-chat.h @@ -57,10 +57,9 @@ EmpathyTpChat *empathy_tp_chat_new (TpChannel *channel void empathy_tp_chat_close (EmpathyTpChat *chat); const gchar * empathy_tp_chat_get_id (EmpathyTpChat *chat); EmpathyContact*empathy_tp_chat_get_remote_contact (EmpathyTpChat *chat); -McAccount * empathy_tp_chat_get_account (EmpathyTpChat *chat); TpChannel * empathy_tp_chat_get_channel (EmpathyTpChat *chat); +TpConnection * empathy_tp_chat_get_connection (EmpathyTpChat *chat); gboolean empathy_tp_chat_is_ready (EmpathyTpChat *chat); -guint empathy_tp_chat_get_members_count (EmpathyTpChat *chat); void empathy_tp_chat_send (EmpathyTpChat *chat, EmpathyMessage *message); void empathy_tp_chat_set_state (EmpathyTpChat *chat, diff --git a/libempathy/empathy-tp-contact-factory.c b/libempathy/empathy-tp-contact-factory.c index f72cc77d..7735b0f1 100644 --- a/libempathy/empathy-tp-contact-factory.c +++ b/libempathy/empathy-tp-contact-factory.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,28 +24,20 @@ #include #include -#include #include -#include #include #include "empathy-tp-contact-factory.h" #include "empathy-utils.h" -#include "empathy-account-manager.h" #define DEBUG_FLAG EMPATHY_DEBUG_TP | EMPATHY_DEBUG_CONTACT #include "empathy-debug.h" #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyTpContactFactory) typedef struct { - EmpathyAccountManager *account_manager; - McAccount *account; TpConnection *connection; - gboolean ready; - GList *contacts; - EmpathyContact *user; gchar **avatar_mime_types; guint avatar_min_width; @@ -53,15 +45,14 @@ typedef struct { guint avatar_max_width; guint avatar_max_height; guint avatar_max_size; - gboolean can_request_ft; + gboolean can_request_ft; } EmpathyTpContactFactoryPriv; G_DEFINE_TYPE (EmpathyTpContactFactory, empathy_tp_contact_factory, G_TYPE_OBJECT); enum { PROP_0, - PROP_ACCOUNT, - PROP_READY, + PROP_CONNECTION, PROP_MIME_TYPES, PROP_MIN_WIDTH, @@ -71,6 +62,11 @@ enum { PROP_MAX_SIZE }; +static TpContactFeature contact_features[] = { + TP_CONTACT_FEATURE_ALIAS, + TP_CONTACT_FEATURE_PRESENCE, +}; + static EmpathyContact * tp_contact_factory_find_by_handle (EmpathyTpContactFactory *tp_factory, guint handle) @@ -88,14 +84,14 @@ tp_contact_factory_find_by_handle (EmpathyTpContactFactory *tp_factory, } static EmpathyContact * -tp_contact_factory_find_by_id (EmpathyTpContactFactory *tp_factory, - const gchar *id) +tp_contact_factory_find_by_tp_contact (EmpathyTpContactFactory *tp_factory, + TpContact *tp_contact) { EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); GList *l; for (l = priv->contacts; l; l = l->next) { - if (!tp_strdiff (empathy_contact_get_id (l->data), id)) { + if (empathy_contact_get_tp_contact (l->data) == tp_contact) { return l->data; } } @@ -114,104 +110,6 @@ tp_contact_factory_weak_notify (gpointer data, priv->contacts = g_list_remove (priv->contacts, where_the_object_was); } -static void -tp_contact_factory_presences_table_foreach (const gchar *state_str, - GHashTable *presences_table, - EmpathyContact *contact) -{ - const GValue *message; - const gchar *message_str = NULL; - - empathy_contact_set_presence (contact, - empathy_presence_from_str (state_str)); - - message = g_hash_table_lookup (presences_table, "message"); - if (message) { - message_str = g_value_get_string (message); - } - - if (!EMP_STR_EMPTY (message_str)) { - empathy_contact_set_presence_message (contact, message_str); - } else { - empathy_contact_set_presence_message (contact, NULL); - } -} - -static void -tp_contact_factory_parse_presence_foreach (guint handle, - GValueArray *presence_struct, - EmpathyTpContactFactory *tp_factory) -{ - GHashTable *presences_table; - EmpathyContact *contact; - - contact = tp_contact_factory_find_by_handle (tp_factory, handle); - if (!contact) { - return; - } - - presences_table = g_value_get_boxed (g_value_array_get_nth (presence_struct, 1)); - - g_hash_table_foreach (presences_table, - (GHFunc) tp_contact_factory_presences_table_foreach, - contact); - - DEBUG ("Changing presence for contact %s (%d) to '%s' (%d)", - empathy_contact_get_id (contact), - handle, - empathy_contact_get_presence_message (contact), - empathy_contact_get_presence (contact)); -} - -static void -tp_contact_factory_get_presence_cb (TpConnection *connection, - GHashTable *handle_table, - const GError *error, - gpointer user_data, - GObject *tp_factory) -{ - if (error) { - DEBUG ("Error getting presence: %s", error->message); - if (error->domain == TP_DBUS_ERRORS && - error->code == TP_DBUS_ERROR_NO_INTERFACE) { - guint *handles = user_data; - - /* We have no presence iface, set default presence - * to available */ - while (*handles != 0) { - EmpathyContact *contact; - - contact = tp_contact_factory_find_by_handle ( - (EmpathyTpContactFactory*) tp_factory, - *handles); - if (contact) { - empathy_contact_set_presence (contact, - MC_PRESENCE_AVAILABLE); - } - - handles++; - } - } - - return; - } - - g_hash_table_foreach (handle_table, - (GHFunc) tp_contact_factory_parse_presence_foreach, - EMPATHY_TP_CONTACT_FACTORY (tp_factory)); -} - -static void -tp_contact_factory_presence_update_cb (TpConnection *connection, - GHashTable *handle_table, - gpointer user_data, - GObject *tp_factory) -{ - g_hash_table_foreach (handle_table, - (GHFunc) tp_contact_factory_parse_presence_foreach, - EMPATHY_TP_CONTACT_FACTORY (tp_factory)); -} - static void tp_contact_factory_set_aliases_cb (TpConnection *connection, const GError *error, @@ -219,92 +117,7 @@ tp_contact_factory_set_aliases_cb (TpConnection *connection, GObject *tp_factory) { if (error) { - DEBUG ("Error setting alias: %s", error->message); - } -} - -static void -tp_contact_factory_request_aliases_cb (TpConnection *connection, - const gchar **contact_names, - const GError *error, - gpointer user_data, - GObject *tp_factory) -{ - guint *handles = user_data; - guint i = 0; - const gchar **name; - - if (error) { - DEBUG ("Error requesting aliases: %s", error->message); - - /* If we failed to get alias set it to NULL, like that if - * someone is waiting for the name to be ready it won't wait - * infinitely */ - while (*handles != 0) { - EmpathyContact *contact; - - contact = tp_contact_factory_find_by_handle ( - (EmpathyTpContactFactory*) tp_factory, - *handles); - if (contact) { - empathy_contact_set_name (contact, NULL); - } - - handles++; - } - return; - } - - for (name = contact_names; *name; name++) { - EmpathyContact *contact; - - contact = tp_contact_factory_find_by_handle (EMPATHY_TP_CONTACT_FACTORY (tp_factory), - handles[i]); - if (!contact) { - continue; - } - - DEBUG ("Renaming contact %s (%d) to %s (request cb)", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - *name); - - empathy_contact_set_name (contact, *name); - - i++; - } -} - -static void -tp_contact_factory_aliases_changed_cb (TpConnection *connection, - const GPtrArray *renamed_handlers, - gpointer user_data, - GObject *weak_object) -{ - EmpathyTpContactFactory *tp_factory = EMPATHY_TP_CONTACT_FACTORY (weak_object); - guint i; - - for (i = 0; renamed_handlers->len > i; i++) { - guint handle; - const gchar *alias; - GValueArray *renamed_struct; - EmpathyContact *contact; - - renamed_struct = g_ptr_array_index (renamed_handlers, i); - handle = g_value_get_uint (g_value_array_get_nth (renamed_struct, 0)); - alias = g_value_get_string (g_value_array_get_nth (renamed_struct, 1)); - contact = tp_contact_factory_find_by_handle (tp_factory, handle); - - if (!contact) { - /* We don't know this contact, skip */ - continue; - } - - DEBUG ("Renaming contact %s (%d) to %s (changed cb)", - empathy_contact_get_id (contact), - handle, alias); - - empathy_contact_set_name (contact, alias); + DEBUG ("Error: %s", error->message); } } @@ -316,7 +129,7 @@ tp_contact_factory_set_avatar_cb (TpConnection *connection, GObject *tp_factory) { if (error) { - DEBUG ("Error setting avatar: %s", error->message); + DEBUG ("Error: %s", error->message); } } @@ -327,7 +140,7 @@ tp_contact_factory_clear_avatar_cb (TpConnection *connection, GObject *tp_factory) { if (error) { - DEBUG ("Error clearing avatar: %s", error->message); + DEBUG ("Error: %s", error->message); } } @@ -366,7 +179,7 @@ tp_contact_factory_request_avatars_cb (TpConnection *connection, GObject *tp_factory) { if (error) { - DEBUG ("Error requesting avatars: %s", error->message); + DEBUG ("Error: %s", error->message); } } @@ -426,20 +239,19 @@ tp_contact_factory_avatar_tokens_foreach (gpointer key, } static void -tp_contact_factory_get_known_avatar_tokens_cb (TpConnection *connection, - GHashTable *tokens, - const GError *error, - gpointer user_data, - GObject *tp_factory) +tp_contact_factory_got_known_avatar_tokens (EmpathyTpContactFactory *tp_factory, + GHashTable *tokens, + const GError *error) { + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); TokensData data; if (error) { - DEBUG ("Error getting known avatars tokens: %s", error->message); + DEBUG ("Error: %s", error->message); return; } - data.tp_factory = EMPATHY_TP_CONTACT_FACTORY (tp_factory); + data.tp_factory = tp_factory; data.handles = g_array_new (FALSE, FALSE, sizeof (guint)); g_hash_table_foreach (tokens, tp_contact_factory_avatar_tokens_foreach, @@ -450,15 +262,16 @@ tp_contact_factory_get_known_avatar_tokens_cb (TpConnection *connection, /* Request needed avatars */ if (data.handles->len > 0) { - tp_cli_connection_interface_avatars_call_request_avatars (connection, + tp_cli_connection_interface_avatars_call_request_avatars (priv->connection, -1, data.handles, tp_contact_factory_request_avatars_cb, NULL, NULL, - tp_factory); + G_OBJECT (tp_factory)); } g_array_free (data.handles, TRUE); + g_hash_table_destroy (tokens); } static void @@ -528,17 +341,14 @@ tp_contact_factory_update_capabilities (EmpathyTpContactFactory *tp_factory, } static void -tp_contact_factory_get_capabilities_cb (TpConnection *connection, - const GPtrArray *capabilities, - const GError *error, - gpointer user_data, - GObject *weak_object) +tp_contact_factory_got_capabilities (EmpathyTpContactFactory *tp_factory, + GPtrArray *capabilities, + const GError *error) { - EmpathyTpContactFactory *tp_factory = EMPATHY_TP_CONTACT_FACTORY (weak_object); - guint i; + guint i; if (error) { - DEBUG ("Error getting capabilities: %s", error->message); + DEBUG ("Error: %s", error->message); /* FIXME Should set the capabilities of the contacts for which this request * originated to NONE */ return; @@ -562,7 +372,11 @@ tp_contact_factory_get_capabilities_cb (TpConnection *connection, channel_type, generic, specific); + + g_value_array_free (values); } + + g_ptr_array_free (capabilities, TRUE); } static void @@ -595,231 +409,6 @@ tp_contact_factory_capabilities_changed_cb (TpConnection *connection, } } -static void -tp_contact_factory_request_everything (EmpathyTpContactFactory *tp_factory, - const GArray *handles) -{ - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - guint *dup_handles; - - g_return_if_fail (priv->ready); - - dup_handles = g_malloc0 ((handles->len + 1) * sizeof (guint)); - g_memmove (dup_handles, handles->data, handles->len * sizeof (guint)); - tp_cli_connection_interface_presence_call_get_presence (priv->connection, - -1, - handles, - tp_contact_factory_get_presence_cb, - dup_handles, g_free, - G_OBJECT (tp_factory)); - - /* FIXME: Sometimes the dbus call timesout because CM takes - * too much time to request all aliases from the server, - * that's why we increase the timeout here. See fd.o bug #14795 */ - dup_handles = g_malloc0 ((handles->len + 1) * sizeof (guint)); - g_memmove (dup_handles, handles->data, handles->len * sizeof (guint)); - tp_cli_connection_interface_aliasing_call_request_aliases (priv->connection, - 5*60*1000, - handles, - tp_contact_factory_request_aliases_cb, - dup_handles, g_free, - G_OBJECT (tp_factory)); - - tp_cli_connection_interface_avatars_call_get_known_avatar_tokens (priv->connection, - -1, - handles, - tp_contact_factory_get_known_avatar_tokens_cb, - NULL, NULL, - G_OBJECT (tp_factory)); - - tp_cli_connection_interface_capabilities_call_get_capabilities (priv->connection, - -1, - handles, - tp_contact_factory_get_capabilities_cb, - NULL, NULL, - G_OBJECT (tp_factory)); -} - -static void -tp_contact_factory_list_free (gpointer data) -{ - GList *l = data; - - g_list_foreach (l, (GFunc) g_object_unref, NULL); - g_list_free (l); -} - -static void -tp_contact_factory_request_handles_cb (TpConnection *connection, - const GArray *handles, - const GError *error, - gpointer user_data, - GObject *tp_factory) -{ - GList *contacts = user_data; - GList *l; - guint i = 0; - - if (error) { - DEBUG ("Failed to request handles: %s", error->message); - return; - } - - for (l = contacts; l; l = l->next) { - guint handle; - - handle = g_array_index (handles, guint, i); - empathy_contact_set_handle (l->data, handle); - - i++; - } - - tp_contact_factory_request_everything (EMPATHY_TP_CONTACT_FACTORY (tp_factory), - handles); -} - -static void -tp_contact_factory_inspect_handles_cb (TpConnection *connection, - const gchar **ids, - const GError *error, - gpointer user_data, - GObject *tp_factory) -{ - const gchar **id; - GList *contacts = user_data; - GList *l; - - if (error) { - DEBUG ("Failed to inspect handles: %s", error->message); - return; - } - - id = ids; - for (l = contacts; l; l = l->next) { - empathy_contact_set_id (l->data, *id); - id++; - } -} - -static void -tp_contact_factory_disconnect_contact_foreach (gpointer data, - gpointer user_data) -{ - EmpathyContact *contact = data; - - empathy_contact_set_presence (contact, MC_PRESENCE_UNSET); - empathy_contact_set_handle (contact, 0); -} - -static void -tp_contact_factory_connection_invalidated_cb (EmpathyTpContactFactory *tp_factory) -{ - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - - DEBUG ("Connection invalidated"); - - g_object_unref (priv->connection); - priv->connection = NULL; - priv->ready = FALSE; - g_object_notify (G_OBJECT (tp_factory), "ready"); - - - g_list_foreach (priv->contacts, - tp_contact_factory_disconnect_contact_foreach, - tp_factory); -} - -static void -tp_contact_factory_ready (EmpathyTpContactFactory *tp_factory) -{ - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - GList *l; - GArray *handle_needed; - GArray *id_needed; - GList *handle_needed_contacts = NULL; - GList *id_needed_contacts = NULL; - - DEBUG ("Connection ready"); - - priv->ready = TRUE; - g_object_notify (G_OBJECT (tp_factory), "ready"); - - /* Connect signals */ - tp_cli_connection_interface_aliasing_connect_to_aliases_changed (priv->connection, - tp_contact_factory_aliases_changed_cb, - NULL, NULL, - G_OBJECT (tp_factory), - NULL); - tp_cli_connection_interface_avatars_connect_to_avatar_updated (priv->connection, - tp_contact_factory_avatar_updated_cb, - NULL, NULL, - G_OBJECT (tp_factory), - NULL); - tp_cli_connection_interface_avatars_connect_to_avatar_retrieved (priv->connection, - tp_contact_factory_avatar_retrieved_cb, - NULL, NULL, - G_OBJECT (tp_factory), - NULL); - tp_cli_connection_interface_presence_connect_to_presence_update (priv->connection, - tp_contact_factory_presence_update_cb, - NULL, NULL, - G_OBJECT (tp_factory), - NULL); - tp_cli_connection_interface_capabilities_connect_to_capabilities_changed (priv->connection, - tp_contact_factory_capabilities_changed_cb, - NULL, NULL, - G_OBJECT (tp_factory), - NULL); - - /* Request needed info for all existing contacts */ - handle_needed = g_array_new (TRUE, FALSE, sizeof (gchar*)); - id_needed = g_array_new (FALSE, FALSE, sizeof (guint)); - for (l = priv->contacts; l; l = l->next) { - EmpathyContact *contact; - guint handle; - const gchar *id; - - contact = l->data; - handle = empathy_contact_get_handle (contact); - id = empathy_contact_get_id (contact); - if (handle == 0) { - g_assert (!EMP_STR_EMPTY (id)); - g_array_append_val (handle_needed, id); - handle_needed_contacts = g_list_prepend (handle_needed_contacts, - g_object_ref (contact)); - } - if (EMP_STR_EMPTY (id)) { - g_array_append_val (id_needed, handle); - id_needed_contacts = g_list_prepend (id_needed_contacts, - g_object_ref (contact)); - } - } - handle_needed_contacts = g_list_reverse (handle_needed_contacts); - id_needed_contacts = g_list_reverse (id_needed_contacts); - - tp_cli_connection_call_request_handles (priv->connection, - -1, - TP_HANDLE_TYPE_CONTACT, - (const gchar**) handle_needed->data, - tp_contact_factory_request_handles_cb, - handle_needed_contacts, tp_contact_factory_list_free, - G_OBJECT (tp_factory)); - - tp_cli_connection_call_inspect_handles (priv->connection, - -1, - TP_HANDLE_TYPE_CONTACT, - id_needed, - tp_contact_factory_inspect_handles_cb, - id_needed_contacts, tp_contact_factory_list_free, - G_OBJECT (tp_factory)); - - tp_contact_factory_request_everything ((EmpathyTpContactFactory*) tp_factory, - id_needed); - - g_array_free (handle_needed, TRUE); - g_array_free (id_needed, TRUE); -} - static void get_requestable_channel_classes_cb (TpProxy *connection, const GValue *value, @@ -834,7 +423,6 @@ get_requestable_channel_classes_cb (TpProxy *connection, if (error != NULL) { DEBUG ("Error: %s", error->message); - tp_contact_factory_ready (self); return; } @@ -877,8 +465,6 @@ get_requestable_channel_classes_cb (TpProxy *connection, } break; } - - tp_contact_factory_ready (self); } static void @@ -909,303 +495,377 @@ tp_contact_factory_got_avatar_requirements_cb (TpConnection *proxy, priv->avatar_max_height = max_height; priv->avatar_max_size = max_size; } - - /* Can we request file transfer channels? */ - tp_cli_dbus_properties_call_get (priv->connection, -1, - TP_IFACE_CONNECTION_INTERFACE_REQUESTS, - "RequestableChannelClasses", - get_requestable_channel_classes_cb, NULL, NULL, - G_OBJECT (tp_factory)); } static void -tp_contact_factory_got_self_handle_cb (TpConnection *proxy, - guint handle, - const GError *error, - gpointer user_data, - GObject *tp_factory) +tp_contact_factory_add_contact (EmpathyTpContactFactory *tp_factory, + EmpathyContact *contact) { EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + TpHandle self_handle; + TpHandle handle; + GArray handles = {(gchar*) &handle, 1}; + GHashTable *tokens; + GPtrArray *capabilities; + GError *error = NULL; + + /* Keep a weak ref to that contact */ + g_object_weak_ref (G_OBJECT (contact), + tp_contact_factory_weak_notify, + tp_factory); + priv->contacts = g_list_prepend (priv->contacts, contact); - if (error) { - DEBUG ("Failed to get self handles: %s", error->message); - return; + /* The contact keeps a ref to its factory */ + g_object_set_data_full (G_OBJECT (contact), "empathy-factory", + g_object_ref (tp_factory), + g_object_unref); + + /* Set the FT capability */ + if (priv->can_request_ft) { + EmpathyCapabilities caps; + + caps = empathy_contact_get_capabilities (contact); + caps |= EMPATHY_CAPABILITIES_FT; + + empathy_contact_set_capabilities (contact, caps); } - empathy_contact_set_handle (priv->user, handle); + /* Set is-user property. Note that it could still be the handle is + * different from the connection's self handle, in the case the handle + * comes from a group interface. */ + self_handle = tp_connection_get_self_handle (priv->connection); + handle = empathy_contact_get_handle (contact); + empathy_contact_set_is_user (contact, self_handle == handle); + + /* FIXME: This should be done by TpContact */ + tp_cli_connection_interface_avatars_run_get_known_avatar_tokens (priv->connection, + -1, + &handles, + &tokens, + &error, + NULL); + tp_contact_factory_got_known_avatar_tokens (tp_factory, tokens, error); + g_clear_error (&error); + + tp_cli_connection_interface_capabilities_run_get_capabilities (priv->connection, + -1, + &handles, + &capabilities, + &error, + NULL); + tp_contact_factory_got_capabilities (tp_factory, capabilities, error); + g_clear_error (&error); - /* Get avatar requirements for this connection */ - tp_cli_connection_interface_avatars_call_get_avatar_requirements ( - priv->connection, - -1, - tp_contact_factory_got_avatar_requirements_cb, - NULL, NULL, - tp_factory); + DEBUG ("Contact added: %s (%d)", + empathy_contact_get_id (contact), + empathy_contact_get_handle (contact)); } -static void -tp_contact_factory_connection_ready_cb (EmpathyTpContactFactory *tp_factory) -{ - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); +typedef union { + EmpathyTpContactFactoryContactsByIdCb ids_cb; + EmpathyTpContactFactoryContactsByHandleCb handles_cb; + EmpathyTpContactFactoryContactCb contact_cb; +} GetContactsCb; - /* Get our own handle */ - tp_cli_connection_call_get_self_handle (priv->connection, - -1, - tp_contact_factory_got_self_handle_cb, - NULL, NULL, - G_OBJECT (tp_factory)); -} +typedef struct { + EmpathyTpContactFactory *tp_factory; + GetContactsCb callback; + gpointer user_data; + GDestroyNotify destroy; +} GetContactsData; static void -tp_contact_factory_status_updated (EmpathyTpContactFactory *tp_factory) +get_contacts_data_free (gpointer user_data) { - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - gboolean connection_ready; - MissionControl *mc; + GetContactsData *data = user_data; - if (priv->connection) { - /* We already have our connection object */ - return; + if (data->destroy) { + data->destroy (data->user_data); } + g_object_unref (data->tp_factory); - mc = empathy_mission_control_dup_singleton (); - priv->connection = mission_control_get_tpconnection (mc, priv->account, NULL); - if (!priv->connection) { - return; - } + g_slice_free (GetContactsData, data); +} - /* We got a new connection, wait for it to be ready */ - g_signal_connect_swapped (priv->connection, "invalidated", - G_CALLBACK (tp_contact_factory_connection_invalidated_cb), - tp_factory); +static EmpathyContact * +dup_contact_for_tp_contact (EmpathyTpContactFactory *tp_factory, + TpContact *tp_contact) +{ + EmpathyContact *contact; + + contact = tp_contact_factory_find_by_tp_contact (tp_factory, + tp_contact); - g_object_get (priv->connection, "connection-ready", &connection_ready, NULL); - if (connection_ready) { - tp_contact_factory_connection_ready_cb (tp_factory); + if (contact != NULL) { + g_object_ref (contact); } else { - g_signal_connect_swapped (priv->connection, "notify::connection-ready", - G_CALLBACK (tp_contact_factory_connection_ready_cb), - tp_factory); + contact = empathy_contact_new (tp_contact); + tp_contact_factory_add_contact (tp_factory, contact); } - g_object_unref (mc); + return contact; } -static void -tp_contact_factory_account_connection_cb (EmpathyAccountManager *account_manager, - McAccount *account, - TpConnectionStatusReason reason, - TpConnectionStatus current, - TpConnectionStatus previous, - EmpathyTpContactFactory *tp_factory) +static EmpathyContact ** +contacts_array_new (EmpathyTpContactFactory *tp_factory, + guint n_contacts, + TpContact * const * contacts) { - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + EmpathyContact **ret; + guint i; - if (account && empathy_account_equal (account, priv->account)) { - tp_contact_factory_status_updated (tp_factory); + ret = g_new0 (EmpathyContact *, n_contacts); + for (i = 0; i < n_contacts; i++) { + ret[i] = dup_contact_for_tp_contact (tp_factory, contacts[i]); } + + return ret; } static void -tp_contact_factory_add_contact (EmpathyTpContactFactory *tp_factory, - EmpathyContact *contact) +contacts_array_free (guint n_contacts, + EmpathyContact **contacts) { - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - - g_object_weak_ref (G_OBJECT (contact), - tp_contact_factory_weak_notify, - tp_factory); - priv->contacts = g_list_prepend (priv->contacts, contact); + guint i; - DEBUG ("Contact added: %s (%d)", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact)); + for (i = 0; i < n_contacts; i++) { + g_object_unref (contacts[i]); + } + g_free (contacts); } static void -tp_contact_factory_hold_handles_cb (TpConnection *connection, - const GError *error, - gpointer userdata, - GObject *tp_factory) +get_contacts_by_id_cb (TpConnection *connection, + guint n_contacts, + TpContact * const *contacts, + const gchar * const *requested_ids, + GHashTable *failed_id_errors, + const GError *error, + gpointer user_data, + GObject *weak_object) { - if (error) { - DEBUG ("Failed to hold handles: %s", error->message); + GetContactsData *data = user_data; + EmpathyContact **empathy_contacts; + + empathy_contacts = contacts_array_new (data->tp_factory, + n_contacts, contacts); + if (data->callback.ids_cb) { + data->callback.ids_cb (data->tp_factory, + n_contacts, empathy_contacts, + requested_ids, + failed_id_errors, + error, + data->user_data, weak_object); } + + contacts_array_free (n_contacts, empathy_contacts); } -EmpathyContact * -empathy_tp_contact_factory_get_user (EmpathyTpContactFactory *tp_factory) +void +empathy_tp_contact_factory_get_from_ids (EmpathyTpContactFactory *tp_factory, + guint n_ids, + const gchar * const *ids, + EmpathyTpContactFactoryContactsByIdCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object) { EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + GetContactsData *data; - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL); - - return g_object_ref (priv->user); + g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory)); + g_return_if_fail (ids != NULL); + + data = g_slice_new (GetContactsData); + data->callback.ids_cb = callback; + data->user_data = user_data; + data->destroy = destroy; + data->tp_factory = g_object_ref (tp_factory); + tp_connection_get_contacts_by_id (priv->connection, + n_ids, ids, + G_N_ELEMENTS (contact_features), + contact_features, + get_contacts_by_id_cb, + data, + (GDestroyNotify) get_contacts_data_free, + weak_object); } static void -contact_created (EmpathyTpContactFactory *self, - EmpathyContact *contact) +get_contact_by_id_cb (TpConnection *connection, + guint n_contacts, + TpContact * const *contacts, + const gchar * const *requested_ids, + GHashTable *failed_id_errors, + const GError *error, + gpointer user_data, + GObject *weak_object) { - EmpathyTpContactFactoryPriv *priv = GET_PRIV (self); - - if (priv->can_request_ft) - { - /* Set the FT capability */ - /* FIXME: We should use the futur ContactCapabilities interface */ - EmpathyCapabilities caps; - - caps = empathy_contact_get_capabilities (contact); - caps |= EMPATHY_CAPABILITIES_FT; + GetContactsData *data = user_data; + EmpathyContact *contact = NULL; - empathy_contact_set_capabilities (contact, caps); - } + if (n_contacts == 1) { + contact = dup_contact_for_tp_contact (data->tp_factory, + contacts[0]); + } + else if (error == NULL) { + GHashTableIter iter; + gpointer value; + + g_hash_table_iter_init (&iter, failed_id_errors); + while (g_hash_table_iter_next (&iter, NULL, &value)) { + if (value) { + error = value; + break; + } + } + } - tp_contact_factory_add_contact (self, contact); + if (data->callback.contact_cb) { + data->callback.contact_cb (data->tp_factory, + contact, + error, + data->user_data, weak_object); + } } -EmpathyContact * +void empathy_tp_contact_factory_get_from_id (EmpathyTpContactFactory *tp_factory, - const gchar *id) + const gchar *id, + EmpathyTpContactFactoryContactCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object) { EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - EmpathyContact *contact; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL); - g_return_val_if_fail (id != NULL, NULL); - - /* Check if the contact already exists */ - contact = tp_contact_factory_find_by_id (tp_factory, id); - if (contact) { - return g_object_ref (contact); - } - - /* Create new contact */ - contact = g_object_new (EMPATHY_TYPE_CONTACT, - "account", priv->account, - "id", id, - NULL); - contact_created (tp_factory, contact); - - if (priv->ready) { - const gchar *contact_ids[] = {id, NULL}; - GList *contacts; - - contacts = g_list_prepend (NULL, g_object_ref (contact)); - tp_cli_connection_call_request_handles (priv->connection, - -1, - TP_HANDLE_TYPE_CONTACT, - contact_ids, - tp_contact_factory_request_handles_cb, - contacts, tp_contact_factory_list_free, - G_OBJECT (tp_factory)); - } + GetContactsData *data; - return contact; + g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory)); + g_return_if_fail (id != NULL); + + data = g_slice_new (GetContactsData); + data->callback.contact_cb = callback; + data->user_data = user_data; + data->destroy = destroy; + data->tp_factory = g_object_ref (tp_factory); + tp_connection_get_contacts_by_id (priv->connection, + 1, &id, + G_N_ELEMENTS (contact_features), + contact_features, + get_contact_by_id_cb, + data, + (GDestroyNotify) get_contacts_data_free, + weak_object); } -EmpathyContact * -empathy_tp_contact_factory_get_from_handle (EmpathyTpContactFactory *tp_factory, - guint handle) +static void +get_contacts_by_handle_cb (TpConnection *connection, + guint n_contacts, + TpContact * const *contacts, + guint n_failed, + const TpHandle *failed, + const GError *error, + gpointer user_data, + GObject *weak_object) { - EmpathyContact *contact; - GArray *handles; - GList *contacts; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL); - - handles = g_array_new (FALSE, FALSE, sizeof (guint)); - g_array_append_val (handles, handle); - - contacts = empathy_tp_contact_factory_get_from_handles (tp_factory, handles); - g_array_free (handles, TRUE); - - contact = contacts ? contacts->data : NULL; - g_list_free (contacts); + GetContactsData *data = user_data; + EmpathyContact **empathy_contacts; + + empathy_contacts = contacts_array_new (data->tp_factory, + n_contacts, contacts); + if (data->callback.handles_cb) { + data->callback.handles_cb (data->tp_factory, + n_contacts, empathy_contacts, + n_failed, failed, + error, + data->user_data, weak_object); + } - return contact; + contacts_array_free (n_contacts, empathy_contacts); } -GList * +void empathy_tp_contact_factory_get_from_handles (EmpathyTpContactFactory *tp_factory, - const GArray *handles) + guint n_handles, + const TpHandle *handles, + EmpathyTpContactFactoryContactsByHandleCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object) { EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - GList *contacts = NULL; - GArray *new_handles; - GList *new_contacts = NULL; - guint i; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL); - g_return_val_if_fail (handles != NULL, NULL); + GetContactsData *data; - /* Search all contacts we already have */ - new_handles = g_array_new (FALSE, FALSE, sizeof (guint)); - for (i = 0; i < handles->len; i++) { - EmpathyContact *contact; - guint handle; + g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory)); + g_return_if_fail (handles != NULL); + + data = g_slice_new (GetContactsData); + data->callback.handles_cb = callback; + data->user_data = user_data; + data->destroy = destroy; + data->tp_factory = g_object_ref (tp_factory); + tp_connection_get_contacts_by_handle (priv->connection, + n_handles, handles, + G_N_ELEMENTS (contact_features), + contact_features, + get_contacts_by_handle_cb, + data, + (GDestroyNotify) get_contacts_data_free, + weak_object); +} - handle = g_array_index (handles, guint, i); - if (handle == 0) { - continue; - } +static void +get_contact_by_handle_cb (TpConnection *connection, + guint n_contacts, + TpContact * const *contacts, + guint n_failed, + const TpHandle *failed, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + GetContactsData *data = user_data; + EmpathyContact *contact = NULL; - contact = tp_contact_factory_find_by_handle (tp_factory, handle); - if (contact) { - contacts = g_list_prepend (contacts, g_object_ref (contact)); - } else { - g_array_append_val (new_handles, handle); - } + if (n_contacts == 1) { + contact = dup_contact_for_tp_contact (data->tp_factory, + contacts[0]); } - if (new_handles->len == 0) { - g_array_free (new_handles, TRUE); - return contacts; + if (data->callback.contact_cb) { + data->callback.contact_cb (data->tp_factory, + contact, + error, + data->user_data, weak_object); } +} - /* Create new contacts */ - for (i = 0; i < new_handles->len; i++) { - EmpathyContact *contact; - guint handle; - - handle = g_array_index (new_handles, guint, i); - - contact = g_object_new (EMPATHY_TYPE_CONTACT, - "account", priv->account, - "handle", handle, - NULL); - contact_created (tp_factory, contact); - contacts = g_list_prepend (contacts, contact); - new_contacts = g_list_prepend (new_contacts, g_object_ref (contact)); - } - new_contacts = g_list_reverse (new_contacts); - - if (priv->ready) { - /* Get the IDs of all new handles */ - tp_cli_connection_call_inspect_handles (priv->connection, - -1, - TP_HANDLE_TYPE_CONTACT, - new_handles, - tp_contact_factory_inspect_handles_cb, - new_contacts, tp_contact_factory_list_free, - G_OBJECT (tp_factory)); - - /* Hold all new handles. */ - /* FIXME: Should be unholded when removed from the factory */ - tp_cli_connection_call_hold_handles (priv->connection, - -1, - TP_HANDLE_TYPE_CONTACT, - new_handles, - tp_contact_factory_hold_handles_cb, - NULL, NULL, - G_OBJECT (tp_factory)); - - tp_contact_factory_request_everything (tp_factory, new_handles); - } +void +empathy_tp_contact_factory_get_from_handle (EmpathyTpContactFactory *tp_factory, + TpHandle handle, + EmpathyTpContactFactoryContactCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object) +{ + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + GetContactsData *data; - g_array_free (new_handles, TRUE); + g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory)); - return contacts; + data = g_slice_new (GetContactsData); + data->callback.contact_cb = callback; + data->user_data = user_data; + data->destroy = destroy; + data->tp_factory = g_object_ref (tp_factory); + tp_connection_get_contacts_by_handle (priv->connection, + 1, &handle, + G_N_ELEMENTS (contact_features), + contact_features, + get_contact_by_handle_cb, + data, + (GDestroyNotify) get_contacts_data_free, + weak_object); } void @@ -1219,9 +879,6 @@ empathy_tp_contact_factory_set_alias (EmpathyTpContactFactory *tp_factory, g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory)); g_return_if_fail (EMPATHY_IS_CONTACT (contact)); - g_return_if_fail (priv->ready); - g_return_if_fail (empathy_account_equal (empathy_contact_get_account (contact), - priv->account)); handle = empathy_contact_get_handle (contact); @@ -1257,7 +914,6 @@ empathy_tp_contact_factory_set_avatar (EmpathyTpContactFactory *tp_factory, EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory)); - g_return_if_fail (priv->ready); if (data && size > 0 && size < G_MAXUINT) { GArray avatar; @@ -1265,8 +921,8 @@ empathy_tp_contact_factory_set_avatar (EmpathyTpContactFactory *tp_factory, avatar.data = (gchar*) data; avatar.len = size; - DEBUG ("Setting avatar on account %s", - mc_account_get_unique_name (priv->account)); + DEBUG ("Setting avatar on connection %s", + tp_proxy_get_object_path (TP_PROXY (priv->connection))); tp_cli_connection_interface_avatars_call_set_avatar (priv->connection, -1, @@ -1276,8 +932,8 @@ empathy_tp_contact_factory_set_avatar (EmpathyTpContactFactory *tp_factory, NULL, NULL, G_OBJECT (tp_factory)); } else { - DEBUG ("Clearing avatar on account %s", - mc_account_get_unique_name (priv->account)); + DEBUG ("Clearing avatar on connection %s", + tp_proxy_get_object_path (TP_PROXY (priv->connection))); tp_cli_connection_interface_avatars_call_clear_avatar (priv->connection, -1, @@ -1287,16 +943,6 @@ empathy_tp_contact_factory_set_avatar (EmpathyTpContactFactory *tp_factory, } } -gboolean -empathy_tp_contact_factory_is_ready (EmpathyTpContactFactory *tp_factory) -{ - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), FALSE); - - return priv->ready; -} - static void tp_contact_factory_get_property (GObject *object, guint param_id, @@ -1306,11 +952,8 @@ tp_contact_factory_get_property (GObject *object, EmpathyTpContactFactoryPriv *priv = GET_PRIV (object); switch (param_id) { - case PROP_ACCOUNT: - g_value_set_object (value, priv->account); - break; - case PROP_READY: - g_value_set_boolean (value, priv->ready); + case PROP_CONNECTION: + g_value_set_object (value, priv->connection); break; case PROP_MIME_TYPES: g_value_set_boxed (value, priv->avatar_mime_types); @@ -1345,8 +988,8 @@ tp_contact_factory_set_property (GObject *object, EmpathyTpContactFactoryPriv *priv = GET_PRIV (object); switch (param_id) { - case PROP_ACCOUNT: - priv->account = g_object_ref (g_value_get_object (value)); + case PROP_CONNECTION: + priv->connection = g_value_dup_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -1360,12 +1003,7 @@ tp_contact_factory_finalize (GObject *object) EmpathyTpContactFactoryPriv *priv = GET_PRIV (object); GList *l; - DEBUG ("Finalized: %p (%s)", object, - mc_account_get_normalized_name (priv->account)); - - g_signal_handlers_disconnect_by_func (priv->account_manager, - tp_contact_factory_account_connection_cb, - object); + DEBUG ("Finalized: %p", object); for (l = priv->contacts; l; l = l->next) { g_object_weak_unref (G_OBJECT (l->data), @@ -1374,16 +1012,8 @@ tp_contact_factory_finalize (GObject *object) } g_list_free (priv->contacts); - g_object_unref (priv->account_manager); - g_object_unref (priv->account); - g_object_unref (priv->user); - - if (priv->connection) { - g_signal_handlers_disconnect_by_func (priv->connection, - tp_contact_factory_connection_invalidated_cb, - object); - g_object_unref (priv->connection); - } + + g_object_unref (priv->connection); g_strfreev (priv->avatar_mime_types); @@ -1401,11 +1031,35 @@ tp_contact_factory_constructor (GType type, tp_factory = G_OBJECT_CLASS (empathy_tp_contact_factory_parent_class)->constructor (type, n_props, props); priv = GET_PRIV (tp_factory); - priv->ready = FALSE; - priv->user = empathy_contact_new (priv->account); - empathy_contact_set_is_user (priv->user, TRUE); - tp_contact_factory_add_contact ((EmpathyTpContactFactory*) tp_factory, priv->user); - tp_contact_factory_status_updated (EMPATHY_TP_CONTACT_FACTORY (tp_factory)); + /* FIXME: This should be moved to TpContact */ + tp_cli_connection_interface_avatars_connect_to_avatar_updated (priv->connection, + tp_contact_factory_avatar_updated_cb, + NULL, NULL, + tp_factory, + NULL); + tp_cli_connection_interface_avatars_connect_to_avatar_retrieved (priv->connection, + tp_contact_factory_avatar_retrieved_cb, + NULL, NULL, + tp_factory, + NULL); + tp_cli_connection_interface_capabilities_connect_to_capabilities_changed (priv->connection, + tp_contact_factory_capabilities_changed_cb, + NULL, NULL, + tp_factory, + NULL); + + + /* FIXME: This should be moved to TpConnection */ + tp_cli_connection_interface_avatars_call_get_avatar_requirements (priv->connection, + -1, + tp_contact_factory_got_avatar_requirements_cb, + NULL, NULL, + tp_factory); + tp_cli_dbus_properties_call_get (priv->connection, -1, + TP_IFACE_CONNECTION_INTERFACE_REQUESTS, + "RequestableChannelClasses", + get_requestable_channel_classes_cb, NULL, NULL, + G_OBJECT (tp_factory)); return tp_factory; } @@ -1421,29 +1075,20 @@ empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass) object_class->set_property = tp_contact_factory_set_property; g_object_class_install_property (object_class, - PROP_ACCOUNT, - g_param_spec_object ("account", - "Factory's Account", - "The account associated with the factory", - MC_TYPE_ACCOUNT, + PROP_CONNECTION, + g_param_spec_object ("connection", + "Factory's Connection", + "The connection associated with the factory", + TP_TYPE_CONNECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (object_class, - PROP_READY, - g_param_spec_boolean ("ready", - "Whether the factory is ready", - "TRUE once the factory is ready to be used", - FALSE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_MIME_TYPES, g_param_spec_boxed ("avatar-mime-types", "Supported MIME types for avatars", "Types of images that may be set as " - "avatars on this connection. Only valid " - "once 'ready' becomes TRUE.", + "avatars on this connection.", G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -1451,8 +1096,7 @@ empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass) PROP_MIN_WIDTH, g_param_spec_uint ("avatar-min-width", "Minimum width for avatars", - "Minimum width of avatar that may be set. " - "Only valid once 'ready' becomes TRUE.", + "Minimum width of avatar that may be set.", 0, G_MAXUINT, 0, @@ -1462,8 +1106,7 @@ empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass) PROP_MIN_HEIGHT, g_param_spec_uint ("avatar-min-height", "Minimum height for avatars", - "Minimum height of avatar that may be set. " - "Only valid once 'ready' becomes TRUE.", + "Minimum height of avatar that may be set.", 0, G_MAXUINT, 0, @@ -1474,8 +1117,7 @@ empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass) g_param_spec_uint ("avatar-max-width", "Maximum width for avatars", "Maximum width of avatar that may be set " - "or 0 if there is no maximum. " - "Only valid once 'ready' becomes TRUE.", + "or 0 if there is no maximum.", 0, G_MAXUINT, 0, @@ -1486,8 +1128,7 @@ empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass) g_param_spec_uint ("avatar-max-height", "Maximum height for avatars", "Maximum height of avatar that may be set " - "or 0 if there is no maximum. " - "Only valid once 'ready' becomes TRUE.", + "or 0 if there is no maximum.", 0, G_MAXUINT, 0, @@ -1498,8 +1139,7 @@ empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass) g_param_spec_uint ("avatar-max-size", "Maximum size for avatars in bytes", "Maximum file size of avatar that may be " - "set or 0 if there is no maximum. " - "Only valid once 'ready' becomes TRUE.", + "set or 0 if there is no maximum.", 0, G_MAXUINT, 0, @@ -1517,20 +1157,68 @@ empathy_tp_contact_factory_init (EmpathyTpContactFactory *tp_factory) EMPATHY_TYPE_TP_CONTACT_FACTORY, EmpathyTpContactFactoryPriv); tp_factory->priv = priv; - priv->account_manager = empathy_account_manager_dup_singleton (); + priv->can_request_ft = FALSE; +} - g_signal_connect (priv->account_manager, "account-connection-changed", - G_CALLBACK (tp_contact_factory_account_connection_cb), - tp_factory); +static GHashTable *factories = NULL; - priv->can_request_ft = FALSE; +static void +tp_contact_factory_connection_invalidated_cb (TpProxy *connection, + guint domain, + gint code, + gchar *message, + gpointer user_data) +{ + DEBUG ("Message: %s", message); + g_hash_table_remove (factories, connection); +} + +static void +tp_contact_factory_connection_weak_notify_cb (gpointer connection, + GObject *where_the_object_was) +{ + g_hash_table_remove (factories, connection); +} + +static void +tp_contact_factory_remove_connection (gpointer connection) +{ + g_signal_handlers_disconnect_by_func (connection, + tp_contact_factory_connection_invalidated_cb, NULL); + g_object_unref (connection); } EmpathyTpContactFactory * -empathy_tp_contact_factory_new (McAccount *account) +empathy_tp_contact_factory_dup_singleton (TpConnection *connection) { - return g_object_new (EMPATHY_TYPE_TP_CONTACT_FACTORY, - "account", account, - NULL); + EmpathyTpContactFactory *tp_factory; + + g_return_val_if_fail (TP_IS_CONNECTION (connection), NULL); + + if (factories == NULL) { + factories = g_hash_table_new_full (empathy_proxy_hash, + empathy_proxy_equal, + tp_contact_factory_remove_connection, + NULL); + } + + tp_factory = g_hash_table_lookup (factories, connection); + if (tp_factory == NULL) { + tp_factory = g_object_new (EMPATHY_TYPE_TP_CONTACT_FACTORY, + "connection", connection, + NULL); + g_hash_table_insert (factories, g_object_ref (connection), + tp_factory); + g_object_weak_ref (G_OBJECT (tp_factory), + tp_contact_factory_connection_weak_notify_cb, + connection); + g_signal_connect (connection, "invalidated", + G_CALLBACK (tp_contact_factory_connection_invalidated_cb), + NULL); + } else { + g_object_ref (tp_factory); + } + + return tp_factory; } diff --git a/libempathy/empathy-tp-contact-factory.h b/libempathy/empathy-tp-contact-factory.h index 92e7c298..91ff2f9e 100644 --- a/libempathy/empathy-tp-contact-factory.h +++ b/libempathy/empathy-tp-contact-factory.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,7 +24,7 @@ #include -#include +#include #include "empathy-contact.h" @@ -49,15 +49,58 @@ struct _EmpathyTpContactFactoryClass { GObjectClass parent_class; }; +typedef void (*EmpathyTpContactFactoryContactsByIdCb) (EmpathyTpContactFactory *factory, + guint n_contacts, + EmpathyContact * const * contacts, + const gchar * const * requested_ids, + GHashTable *failed_id_errors, + const GError *error, + gpointer user_data, + GObject *weak_object); + +typedef void (*EmpathyTpContactFactoryContactsByHandleCb) (EmpathyTpContactFactory *factory, + guint n_contacts, + EmpathyContact * const * contacts, + guint n_failed, + const TpHandle *failed, + const GError *error, + gpointer user_data, + GObject *weak_object); + +typedef void (*EmpathyTpContactFactoryContactCb) (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *weak_object); + GType empathy_tp_contact_factory_get_type (void) G_GNUC_CONST; -EmpathyTpContactFactory *empathy_tp_contact_factory_new (McAccount *account); -EmpathyContact * empathy_tp_contact_factory_get_user (EmpathyTpContactFactory *tp_factory); -EmpathyContact * empathy_tp_contact_factory_get_from_id (EmpathyTpContactFactory *tp_factory, - const gchar *id); -EmpathyContact * empathy_tp_contact_factory_get_from_handle (EmpathyTpContactFactory *tp_factory, - guint handle); -GList * empathy_tp_contact_factory_get_from_handles (EmpathyTpContactFactory *tp_factory, - const GArray *handles); +EmpathyTpContactFactory *empathy_tp_contact_factory_dup_singleton (TpConnection *connection); +void empathy_tp_contact_factory_get_from_ids (EmpathyTpContactFactory *tp_factory, + guint n_ids, + const gchar * const *ids, + EmpathyTpContactFactoryContactsByIdCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object); +void empathy_tp_contact_factory_get_from_handles (EmpathyTpContactFactory *tp_factory, + guint n_handles, + const TpHandle *handles, + EmpathyTpContactFactoryContactsByHandleCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object); +void empathy_tp_contact_factory_get_from_id (EmpathyTpContactFactory *tp_factory, + const gchar *id, + EmpathyTpContactFactoryContactCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object); +void empathy_tp_contact_factory_get_from_handle (EmpathyTpContactFactory *tp_factory, + TpHandle handle, + EmpathyTpContactFactoryContactCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object); void empathy_tp_contact_factory_set_alias (EmpathyTpContactFactory *tp_factory, EmpathyContact *contact, const gchar *alias); @@ -65,7 +108,6 @@ void empathy_tp_contact_factory_set_avatar (EmpathyTpC const gchar *data, gsize size, const gchar *mime_type); -gboolean empathy_tp_contact_factory_is_ready (EmpathyTpContactFactory *tp_factory); G_END_DECLS diff --git a/libempathy/empathy-tp-contact-list.c b/libempathy/empathy-tp-contact-list.c index d4b99e4c..dd160224 100644 --- a/libempathy/empathy-tp-contact-list.c +++ b/libempathy/empathy-tp-contact-list.c @@ -1,7 +1,7 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2007 Xavier Claessens - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -31,8 +31,8 @@ #include #include "empathy-tp-contact-list.h" +#include "empathy-tp-contact-factory.h" #include "empathy-contact-list.h" -#include "empathy-tp-group.h" #include "empathy-utils.h" #define DEBUG_FLAG EMPATHY_DEBUG_TP | EMPATHY_DEBUG_CONTACT @@ -40,18 +40,16 @@ #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyTpContactList) typedef struct { - McAccount *account; + EmpathyTpContactFactory *factory; TpConnection *connection; const gchar *protocol_group; - gboolean ready; - EmpathyTpGroup *publish; - EmpathyTpGroup *subscribe; - GList *members; - GList *pendings; - - GList *groups; - GHashTable *contacts_groups; + TpChannel *publish; + TpChannel *subscribe; + GHashTable *members; /* handle -> EmpathyContact */ + GHashTable *pendings; /* handle -> EmpathyContact */ + GHashTable *groups; /* group name -> TpChannel */ + GHashTable *add_to_group; /* group name -> GArray of handles */ } EmpathyTpContactListPriv; typedef enum { @@ -62,377 +60,536 @@ typedef enum { static void tp_contact_list_iface_init (EmpathyContactListIface *iface); -enum { - DESTROY, - LAST_SIGNAL -}; - enum { PROP_0, - PROP_ACCOUNT, + PROP_CONNECTION, }; -static guint signals[LAST_SIGNAL]; - G_DEFINE_TYPE_WITH_CODE (EmpathyTpContactList, empathy_tp_contact_list, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_CONTACT_LIST, tp_contact_list_iface_init)); static void -tp_contact_list_group_destroy_cb (EmpathyTpGroup *group, - EmpathyTpContactList *list) +tp_contact_list_group_invalidated_cb (TpChannel *channel, + guint domain, + gint code, + gchar *message, + EmpathyTpContactList *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); + const TpIntSet *members; + TpIntSetIter iter; + const gchar *group_name; + + group_name = tp_channel_get_identifier (channel); + DEBUG ("Group %s invalidated. Message: %s", group_name, message); + + /* Signal that all members are not in that group anymore */ + members = tp_channel_group_get_members (channel); + tp_intset_iter_init (&iter, members); + while (tp_intset_iter_next (&iter)) { + EmpathyContact *contact; + + contact = g_hash_table_lookup (priv->members, + GUINT_TO_POINTER (iter.element)); + if (contact == NULL) { + continue; + } - DEBUG ("Group destroyed: %s", empathy_tp_group_get_name (group)); + DEBUG ("Contact %s (%d) removed from group %s", + empathy_contact_get_id (contact), iter.element, + group_name); + g_signal_emit_by_name (list, "groups-changed", contact, + group_name, + FALSE); + } - priv->groups = g_list_remove (priv->groups, group); - g_object_unref (group); + g_hash_table_remove (priv->groups, group_name); } static void -tp_contact_list_group_member_added_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpContactList *list) +tp_contact_list_group_ready_cb (TpChannel *channel, + const GError *error, + gpointer list) { - EmpathyTpContactListPriv *priv = GET_PRIV (list); - const gchar *group_name; - GList **groups; + EmpathyTpContactListPriv *priv = GET_PRIV (list); + const gchar *group_name; - if (!g_list_find (priv->members, contact)) { + if (error) { + DEBUG ("Error: %s", error->message); + g_object_unref (channel); return; } + + group_name = tp_channel_get_identifier (channel); + g_hash_table_insert (priv->groups, (gpointer) group_name, channel); + DEBUG ("Group %s added", group_name); - groups = g_hash_table_lookup (priv->contacts_groups, contact); - if (!groups) { - groups = g_slice_new0 (GList*); - g_hash_table_insert (priv->contacts_groups, - g_object_ref (contact), - groups); - } + g_signal_connect (channel, "invalidated", + G_CALLBACK (tp_contact_list_group_invalidated_cb), + list); - group_name = empathy_tp_group_get_name (group); - if (!g_list_find_custom (*groups, group_name, (GCompareFunc) strcmp)) { - DEBUG ("Contact %s (%d) added to group %s", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - group_name); - *groups = g_list_prepend (*groups, g_strdup (group_name)); - g_signal_emit_by_name (list, "groups-changed", contact, - group_name, - TRUE); + if (priv->add_to_group) { + GArray *handles; + + handles = g_hash_table_lookup (priv->add_to_group, group_name); + if (handles) { + DEBUG ("Adding initial members to group %s", group_name); + tp_cli_channel_interface_group_call_add_members (channel, + -1, handles, NULL, NULL, NULL, NULL, NULL); + g_hash_table_remove (priv->add_to_group, group_name); + } } } static void -tp_contact_list_group_member_removed_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpContactList *list) +tp_contact_list_group_members_changed_cb (TpChannel *channel, + gchar *message, + GArray *added, + GArray *removed, + GArray *local_pending, + GArray *remote_pending, + guint actor, + guint reason, + EmpathyTpContactList *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - const gchar *group_name; - GList **groups, *l; + const gchar *group_name; + gint i; - if (!g_list_find (priv->members, contact)) { - return; - } + group_name = tp_channel_get_identifier (channel); - groups = g_hash_table_lookup (priv->contacts_groups, contact); - if (!groups) { - return; - } + for (i = 0; i < added->len; i++) { + EmpathyContact *contact; + TpHandle handle; + + handle = g_array_index (added, TpHandle, i); + contact = g_hash_table_lookup (priv->members, + GUINT_TO_POINTER (handle)); + if (contact == NULL) { + continue; + } + + DEBUG ("Contact %s (%d) added to group %s", + empathy_contact_get_id (contact), handle, group_name); + g_signal_emit_by_name (list, "groups-changed", contact, + group_name, + TRUE); + } + + for (i = 0; i < removed->len; i++) { + EmpathyContact *contact; + TpHandle handle; + + handle = g_array_index (removed, TpHandle, i); + contact = g_hash_table_lookup (priv->members, + GUINT_TO_POINTER (handle)); + if (contact == NULL) { + continue; + } - group_name = empathy_tp_group_get_name (group); - if ((l = g_list_find_custom (*groups, group_name, (GCompareFunc) strcmp))) { DEBUG ("Contact %s (%d) removed from group %s", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - group_name); - g_free (l->data); - *groups = g_list_delete_link (*groups, l); + empathy_contact_get_id (contact), handle, group_name); + g_signal_emit_by_name (list, "groups-changed", contact, group_name, FALSE); - } + } } -static EmpathyTpGroup * -tp_contact_list_find_group (EmpathyTpContactList *list, - const gchar *group) +static void +tp_contact_list_group_add_channel (EmpathyTpContactList *list, + const gchar *object_path, + const gchar *channel_type, + TpHandleType handle_type, + guint handle) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - GList *l; + TpChannel *channel; - for (l = priv->groups; l; l = l->next) { - if (!tp_strdiff (group, empathy_tp_group_get_name (l->data))) { - return l->data; - } + /* Only accept server-side contact groups */ + if (tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST) || + handle_type != TP_HANDLE_TYPE_GROUP) { + return; + } + + channel = tp_channel_new (priv->connection, + object_path, channel_type, + handle_type, handle, NULL); + + /* TpChannel emits initial set of members just before being ready */ + g_signal_connect (channel, "group-members-changed", + G_CALLBACK (tp_contact_list_group_members_changed_cb), + list); + + /* Give the ref to the callback */ + tp_channel_call_when_ready (channel, + tp_contact_list_group_ready_cb, + list); +} + +static void +tp_contact_list_group_request_channel_cb (TpConnection *connection, + const gchar *object_path, + const GError *error, + gpointer user_data, + GObject *list) +{ + /* The new channel will be handled in NewChannel cb. Here we only + * handle the error if RequestChannel failed */ + if (error) { + DEBUG ("Error: %s", error->message); + return; } - return NULL; } -static TpContactListType -tp_contact_list_get_type (EmpathyTpContactList *list, - EmpathyTpGroup *group) +static void +tp_contact_list_group_request_handles_cb (TpConnection *connection, + const GArray *handles, + const GError *error, + gpointer user_data, + GObject *list) { - const gchar *name; + TpHandle channel_handle; - name = empathy_tp_group_get_name (group); - if (!tp_strdiff (name, "subscribe")) { - return TP_CONTACT_LIST_TYPE_SUBSCRIBE; - } else if (!tp_strdiff (name, "publish")) { - return TP_CONTACT_LIST_TYPE_PUBLISH; + if (error) { + DEBUG ("Error: %s", error->message); + return; } - return TP_CONTACT_LIST_TYPE_UNKNOWN; + channel_handle = g_array_index (handles, TpHandle, 0); + tp_cli_connection_call_request_channel (connection, -1, + TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, + TP_HANDLE_TYPE_GROUP, + channel_handle, + TRUE, + tp_contact_list_group_request_channel_cb, + NULL, NULL, + list); } +/* This function takes ownership of handles array */ static void -tp_contact_list_add_member (EmpathyTpContactList *list, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message) +tp_contact_list_group_add (EmpathyTpContactList *list, + const gchar *group_name, + GArray *handles) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - GList *l; + TpChannel *channel; + const gchar *names[] = {group_name, NULL}; + + /* Search the channel for that group name */ + channel = g_hash_table_lookup (priv->groups, group_name); + if (channel) { + tp_cli_channel_interface_group_call_add_members (channel, -1, + handles, NULL, NULL, NULL, NULL, NULL); + g_array_free (handles, TRUE); + return; + } - /* Add to the list and emit signal */ - priv->members = g_list_prepend (priv->members, g_object_ref (contact)); - g_signal_emit_by_name (list, "members-changed", - contact, actor, reason, message, - TRUE); + /* That group does not exist yet, we have to: + * 1) Request an handle for the group name + * 2) Request a channel + * 3) When NewChannel is emitted, add handles in members + */ + g_hash_table_insert (priv->add_to_group, + g_strdup (group_name), + handles); + tp_cli_connection_call_request_handles (priv->connection, -1, + TP_HANDLE_TYPE_GROUP, names, + tp_contact_list_group_request_handles_cb, + NULL, NULL, + G_OBJECT (list)); +} + +static void +tp_contact_list_got_added_members_cb (EmpathyTpContactFactory *factory, + guint n_contacts, + EmpathyContact * const * contacts, + guint n_failed, + const TpHandle *failed, + const GError *error, + gpointer user_data, + GObject *list) +{ + EmpathyTpContactListPriv *priv = GET_PRIV (list); + guint i; - /* This contact is now member, implicitly accept pending. */ - if (g_list_find (priv->pendings, contact)) { - empathy_tp_group_add_member (priv->publish, contact, ""); + if (error) { + DEBUG ("Error: %s", error->message); + return; } - /* Update groups of the contact */ - for (l = priv->groups; l; l = l->next) { - if (empathy_tp_group_is_member (l->data, contact)) { - tp_contact_list_group_member_added_cb (l->data, contact, - NULL, 0, NULL, - list); + for (i = 0; i < n_contacts; i++) { + EmpathyContact *contact = contacts[i]; + TpHandle handle; + + handle = empathy_contact_get_handle (contact); + if (g_hash_table_lookup (priv->members, GUINT_TO_POINTER (handle))) + continue; + + /* Add to the list and emit signal */ + g_hash_table_insert (priv->members, GUINT_TO_POINTER (handle), + g_object_ref (contact)); + g_signal_emit_by_name (list, "members-changed", contact, + 0, 0, NULL, TRUE); + + /* This contact is now member, implicitly accept pending. */ + if (g_hash_table_lookup (priv->pendings, GUINT_TO_POINTER (handle))) { + GArray handles = {(gchar*) &handle, 1}; + + tp_cli_channel_interface_group_call_add_members (priv->publish, + -1, &handles, NULL, NULL, NULL, NULL, NULL); } } } static void -tp_contact_list_added_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpContactList *list) +tp_contact_list_got_local_pending_cb (EmpathyTpContactFactory *factory, + guint n_contacts, + EmpathyContact * const * contacts, + guint n_failed, + const TpHandle *failed, + const GError *error, + gpointer user_data, + GObject *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - TpContactListType list_type; - - list_type = tp_contact_list_get_type (list, group); - DEBUG ("Contact %s (%d) added to list type %d", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - list_type); - - /* We now get the presence of that contact, add it to members */ - if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && - !g_list_find (priv->members, contact)) { - tp_contact_list_add_member (list, contact, actor, reason, message); + guint i; + + if (error) { + DEBUG ("Error: %s", error->message); + return; } - /* We now send our presence to that contact, remove it from pendings */ - if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && - g_list_find (priv->pendings, contact)) { - g_signal_emit_by_name (list, "pendings-changed", - contact, actor, reason, message, - FALSE); - priv->pendings = g_list_remove (priv->pendings, contact); - g_object_unref (contact); + for (i = 0; i < n_contacts; i++) { + EmpathyContact *contact = contacts[i]; + TpHandle handle; + const gchar *message; + TpChannelGroupChangeReason reason; + + handle = empathy_contact_get_handle (contact); + if (g_hash_table_lookup (priv->members, GUINT_TO_POINTER (handle))) { + GArray handles = {(gchar*) &handle, 1}; + + /* This contact is already member, auto accept. */ + tp_cli_channel_interface_group_call_add_members (priv->publish, + -1, &handles, NULL, NULL, NULL, NULL, NULL); + } + else if (tp_channel_group_get_local_pending_info (priv->publish, + handle, + NULL, + &reason, + &message)) { + /* Add contact to pendings */ + g_hash_table_insert (priv->pendings, GUINT_TO_POINTER (handle), + g_object_ref (contact)); + g_signal_emit_by_name (list, "pendings-changed", contact, + contact, reason, message, TRUE); + } } } static void -tp_contact_list_removed_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpContactList *list) +tp_contact_list_remove_handle (EmpathyTpContactList *list, + GHashTable *table, + TpHandle handle) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - TpContactListType list_type; - - list_type = tp_contact_list_get_type (list, group); - DEBUG ("Contact %s (%d) removed from list type %d", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - list_type); - - /* This contact refuses to send us his presence, remove from members. */ - if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && - g_list_find (priv->members, contact)) { - g_signal_emit_by_name (list, "members-changed", - contact, actor, reason, message, - FALSE); - priv->members = g_list_remove (priv->members, contact); - g_object_unref (contact); - } + EmpathyContact *contact; + const gchar *signal; + + if (table == priv->pendings) + signal = "pendings-changed"; + else if (table == priv->members) + signal = "members-changed"; + else + return; - /* We refuse to send our presence to that contact, remove from pendings */ - if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && - g_list_find (priv->pendings, contact)) { - g_signal_emit_by_name (list, "pendings-changed", - contact, actor, reason, message, + contact = g_hash_table_lookup (table, GUINT_TO_POINTER (handle)); + if (contact) { + g_object_ref (contact); + g_hash_table_remove (table, GUINT_TO_POINTER (handle)); + g_signal_emit_by_name (list, signal, contact, 0, 0, NULL, FALSE); - priv->pendings = g_list_remove (priv->pendings, contact); g_object_unref (contact); } } static void -tp_contact_list_pending_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpContactList *list) +tp_contact_list_publish_group_members_changed_cb (TpChannel *channel, + gchar *message, + GArray *added, + GArray *removed, + GArray *local_pending, + GArray *remote_pending, + TpHandle actor, + TpChannelGroupChangeReason reason, + EmpathyTpContactList *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - TpContactListType list_type; + guint i; - list_type = tp_contact_list_get_type (list, group); - DEBUG ("Contact %s (%d) pending in list type %d", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - list_type); + /* We now send our presence to those contacts, remove them from pendings */ + for (i = 0; i < added->len; i++) { + tp_contact_list_remove_handle (list, priv->pendings, + g_array_index (added, TpHandle, i)); + } - /* We want this contact in our contact list but we don't get its - * presence yet. Add to members anyway. */ - if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && - !g_list_find (priv->members, contact)) { - tp_contact_list_add_member (list, contact, actor, reason, message); + /* We refuse to send our presence to those contacts, remove from pendings */ + for (i = 0; i < removed->len; i++) { + tp_contact_list_remove_handle (list, priv->pendings, + g_array_index (added, TpHandle, i)); } - /* This contact wants our presence, auto accept if he is member, - * otherwise he is pending. */ - if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && - !g_list_find (priv->pendings, contact)) { - if (g_list_find (priv->members, contact)) { - empathy_tp_group_add_member (priv->publish, contact, ""); - } else { - priv->pendings = g_list_prepend (priv->pendings, - g_object_ref (contact)); - g_signal_emit_by_name (list, "pendings-changed", - contact, actor, reason, message, - TRUE); - } + /* Those contacts want our presence, auto accept those that are already + * member, otherwise add in pendings. */ + if (local_pending->len > 0) { + empathy_tp_contact_factory_get_from_handles (priv->factory, + local_pending->len, (TpHandle*) local_pending->data, + tp_contact_list_got_local_pending_cb, NULL, NULL, + G_OBJECT (list)); } } static void -tp_contact_list_invalidated_cb (TpConnection *connection, - guint domain, - gint code, - gchar *message, - EmpathyTpContactList *list) +tp_contact_list_publish_request_channel_cb (TpConnection *connection, + const gchar *object_path, + const GError *error, + gpointer user_data, + GObject *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - GList *l; - DEBUG ("Connection invalidated"); - - /* Remove all contacts */ - for (l = priv->members; l; l = l->next) { - g_signal_emit_by_name (list, "members-changed", l->data, - NULL, 0, NULL, - FALSE); - g_object_unref (l->data); - } - for (l = priv->pendings; l; l = l->next) { - g_signal_emit_by_name (list, "pendings-changed", l->data, - NULL, 0, NULL, - FALSE); - g_object_unref (l->data); + if (error) { + DEBUG ("Error: %s", error->message); + return; } - g_list_free (priv->members); - g_list_free (priv->pendings); - priv->members = NULL; - priv->pendings = NULL; - /* Tell the world to not use us anymore */ - g_signal_emit (list, signals[DESTROY], 0); + priv->publish = tp_channel_new (connection, object_path, + TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, + TP_HANDLE_TYPE_LIST, + GPOINTER_TO_UINT (user_data), + NULL); + + /* TpChannel emits initial set of members just before being ready */ + g_signal_connect (priv->publish, "group-members-changed", + G_CALLBACK (tp_contact_list_publish_group_members_changed_cb), + list); } static void -tp_contact_list_group_list_free (GList **groups) +tp_contact_list_publish_request_handle_cb (TpConnection *connection, + const GArray *handles, + const GError *error, + gpointer user_data, + GObject *list) { - g_list_foreach (*groups, (GFunc) g_free, NULL); - g_list_free (*groups); - g_slice_free (GList*, groups); + TpHandle handle; + + if (error) { + DEBUG ("Error: %s", error->message); + return; + } + + handle = g_array_index (handles, TpHandle, 0); + tp_cli_connection_call_request_channel (connection, -1, + TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, + TP_HANDLE_TYPE_LIST, + handle, + TRUE, + tp_contact_list_publish_request_channel_cb, + GUINT_TO_POINTER (handle), NULL, + list); } static void -tp_contact_list_add_channel (EmpathyTpContactList *list, - const gchar *object_path, - const gchar *channel_type, - TpHandleType handle_type, - guint handle) +tp_contact_list_subscribe_group_members_changed_cb (TpChannel *channel, + gchar *message, + GArray *added, + GArray *removed, + GArray *local_pending, + GArray *remote_pending, + guint actor, + guint reason, + EmpathyTpContactList *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - TpChannel *channel; - EmpathyTpGroup *group; - const gchar *group_name; - GList *contacts, *l; + guint i; + + /* We now get the presence of those contacts, add them to members */ + if (added->len > 0) { + empathy_tp_contact_factory_get_from_handles (priv->factory, + added->len, (TpHandle*) added->data, + tp_contact_list_got_added_members_cb, NULL, NULL, + G_OBJECT (list)); + } - if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST) != 0 || - handle_type != TP_HANDLE_TYPE_GROUP) { - return; + /* Those contacts refuse to send us their presence, remove from members. */ + for (i = 0; i < removed->len; i++) { + tp_contact_list_remove_handle (list, priv->members, + g_array_index (added, TpHandle, i)); } - channel = tp_channel_new (priv->connection, - object_path, channel_type, - handle_type, handle, NULL); + /* We want those contacts in our contact list but we don't get their + * presence yet. Add to members anyway. */ + if (remote_pending->len > 0) { + empathy_tp_contact_factory_get_from_handles (priv->factory, + remote_pending->len, (TpHandle*) remote_pending->data, + tp_contact_list_got_added_members_cb, NULL, NULL, + G_OBJECT (list)); + } +} - group = empathy_tp_group_new (channel); - empathy_run_until_ready (group); - g_object_unref (channel); +static void +tp_contact_list_subscribe_request_channel_cb (TpConnection *connection, + const gchar *object_path, + const GError *error, + gpointer user_data, + GObject *list) +{ + EmpathyTpContactListPriv *priv = GET_PRIV (list); - /* Check if already exists */ - group_name = empathy_tp_group_get_name (group); - if (tp_contact_list_find_group (list, group_name)) { - g_object_unref (group); + if (error) { + DEBUG ("Error: %s", error->message); return; } - /* Add the group */ - DEBUG ("New server-side group: %s", group_name); - priv->groups = g_list_prepend (priv->groups, group); - g_signal_connect (group, "member-added", - G_CALLBACK (tp_contact_list_group_member_added_cb), - list); - g_signal_connect (group, "member-removed", - G_CALLBACK (tp_contact_list_group_member_removed_cb), - list); - g_signal_connect (group, "destroy", - G_CALLBACK (tp_contact_list_group_destroy_cb), + priv->subscribe = tp_channel_new (connection, object_path, + TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, + TP_HANDLE_TYPE_LIST, + GPOINTER_TO_UINT (user_data), + NULL); + + /* TpChannel emits initial set of members just before being ready */ + g_signal_connect (priv->subscribe, "group-members-changed", + G_CALLBACK (tp_contact_list_subscribe_group_members_changed_cb), list); +} - /* Get initial members */ - contacts = empathy_tp_group_get_members (group); - for (l = contacts; l; l = l->next) { - tp_contact_list_group_member_added_cb (group, l->data, - NULL, 0, NULL, - list); - g_object_unref (l->data); +static void +tp_contact_list_subscribe_request_handle_cb (TpConnection *connection, + const GArray *handles, + const GError *error, + gpointer user_data, + GObject *list) +{ + TpHandle handle; + + if (error) { + DEBUG ("Error: %s", error->message); + return; } - g_list_free (contacts); + + handle = g_array_index (handles, TpHandle, 0); + tp_cli_connection_call_request_channel (connection, -1, + TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, + TP_HANDLE_TYPE_LIST, + handle, + TRUE, + tp_contact_list_subscribe_request_channel_cb, + GUINT_TO_POINTER (handle), NULL, + list); } static void @@ -445,13 +602,9 @@ tp_contact_list_new_channel_cb (TpConnection *proxy, gpointer user_data, GObject *list) { - EmpathyTpContactListPriv *priv = GET_PRIV (list); - - if (!suppress_handler && priv->ready) { - tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list), - object_path, channel_type, - handle_type, handle); - } + tp_contact_list_group_add_channel (EMPATHY_TP_CONTACT_LIST (list), + object_path, channel_type, + handle_type, handle); } static void @@ -461,8 +614,7 @@ tp_contact_list_list_channels_cb (TpConnection *connection, gpointer user_data, GObject *list) { - EmpathyTpContactListPriv *priv = GET_PRIV (list); - guint i; + guint i; if (error) { DEBUG ("Error: %s", error->message); @@ -482,151 +634,10 @@ tp_contact_list_list_channels_cb (TpConnection *connection, handle_type = g_value_get_uint (g_value_array_get_nth (chan_struct, 2)); handle = g_value_get_uint (g_value_array_get_nth (chan_struct, 3)); - tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list), - object_path, channel_type, - handle_type, handle); - } - - priv->ready = TRUE; -} - -static void -tp_contact_list_request_channel_cb (TpConnection *connection, - const gchar *object_path, - const GError *error, - gpointer user_data, - GObject *weak_object) -{ - EmpathyTpContactList *list = EMPATHY_TP_CONTACT_LIST (weak_object); - EmpathyTpContactListPriv *priv = GET_PRIV (list); - EmpathyTpGroup *group; - TpChannel *channel; - TpContactListType list_type; - GList *contacts, *l; - - if (error) { - DEBUG ("Error: %s", error->message); - return; - } - - channel = tp_channel_new (connection, object_path, - TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, - TP_HANDLE_TYPE_LIST, - GPOINTER_TO_UINT (user_data), - NULL); - group = empathy_tp_group_new (channel); - empathy_run_until_ready (group); - - list_type = tp_contact_list_get_type (list, group); - if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && !priv->publish) { - DEBUG ("Got publish list"); - priv->publish = group; - - /* Publish is the list of contacts to who we send our - * presence. Makes no sense to be in remote-pending */ - g_signal_connect (group, "local-pending", - G_CALLBACK (tp_contact_list_pending_cb), - list); - - contacts = empathy_tp_group_get_local_pendings (group); - for (l = contacts; l; l = l->next) { - EmpathyPendingInfo *info = l->data; - tp_contact_list_pending_cb (group, - info->member, - info->actor, - 0, - info->message, - list); - empathy_pending_info_free (info); - } - g_list_free (contacts); - } - else if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && !priv->subscribe) { - DEBUG ("Got subscribe list"); - priv->subscribe = group; - - /* Subscribe is the list of contacts from who we - * receive presence. Makes no sense to be in - * local-pending */ - g_signal_connect (group, "remote-pending", - G_CALLBACK (tp_contact_list_pending_cb), - list); - - contacts = empathy_tp_group_get_remote_pendings (group); - for (l = contacts; l; l = l->next) { - tp_contact_list_pending_cb (group, - l->data, - NULL, 0, - NULL, list); - g_object_unref (l->data); - } - g_list_free (contacts); - } else { - DEBUG ("Type of contact list channel unknown or aleady " - "have that list: %s", - empathy_tp_group_get_name (group)); - g_object_unref (group); - return; + tp_contact_list_group_add_channel (EMPATHY_TP_CONTACT_LIST (list), + object_path, channel_type, + handle_type, handle); } - - /* For all list types when need to get members */ - g_signal_connect (group, "member-added", - G_CALLBACK (tp_contact_list_added_cb), - list); - g_signal_connect (group, "member-removed", - G_CALLBACK (tp_contact_list_removed_cb), - list); - - contacts = empathy_tp_group_get_members (group); - for (l = contacts; l; l = l->next) { - tp_contact_list_added_cb (group, - l->data, - NULL, 0, NULL, - list); - g_object_unref (l->data); - } - g_list_free (contacts); -} - -static void -tp_contact_list_request_handle_cb (TpConnection *connection, - const GArray *handles, - const GError *error, - gpointer user_data, - GObject *list) -{ - guint handle; - - if (error) { - DEBUG ("Error: %s", error->message); - return; - } - - handle = g_array_index (handles, guint, 0); - tp_cli_connection_call_request_channel (connection, -1, - TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, - TP_HANDLE_TYPE_LIST, - handle, - TRUE, - tp_contact_list_request_channel_cb, - GUINT_TO_POINTER (handle), NULL, - list); -} - -static void -tp_contact_list_request_list (EmpathyTpContactList *list, - const gchar *type) -{ - EmpathyTpContactListPriv *priv = GET_PRIV (list); - const gchar *names[] = {type, NULL}; - - tp_cli_connection_call_request_handles (priv->connection, - -1, - TP_HANDLE_TYPE_LIST, - names, - tp_contact_list_request_handle_cb, - NULL, NULL, - G_OBJECT (list)); } static void @@ -634,6 +645,8 @@ tp_contact_list_finalize (GObject *object) { EmpathyTpContactListPriv *priv; EmpathyTpContactList *list; + GHashTableIter iter; + gpointer channel; list = EMPATHY_TP_CONTACT_LIST (object); priv = GET_PRIV (list); @@ -646,49 +659,55 @@ tp_contact_list_finalize (GObject *object) if (priv->publish) { g_object_unref (priv->publish); } - if (priv->account) { - g_object_unref (priv->account); - } + if (priv->connection) { - g_signal_handlers_disconnect_by_func (priv->connection, - tp_contact_list_invalidated_cb, - object); g_object_unref (priv->connection); } - g_hash_table_destroy (priv->contacts_groups); - g_list_foreach (priv->groups, (GFunc) g_object_unref, NULL); - g_list_free (priv->groups); - g_list_foreach (priv->members, (GFunc) g_object_unref, NULL); - g_list_free (priv->members); - g_list_foreach (priv->pendings, (GFunc) g_object_unref, NULL); - g_list_free (priv->pendings); + if (priv->factory) { + g_object_unref (priv->factory); + } + + g_hash_table_iter_init (&iter, priv->groups); + while (g_hash_table_iter_next (&iter, NULL, &channel)) { + g_signal_handlers_disconnect_by_func (channel, + tp_contact_list_group_invalidated_cb, list); + } + + g_hash_table_destroy (priv->groups); + g_hash_table_destroy (priv->members); + g_hash_table_destroy (priv->pendings); + g_hash_table_destroy (priv->add_to_group); G_OBJECT_CLASS (empathy_tp_contact_list_parent_class)->finalize (object); } static void -tp_contact_list_connection_ready (TpConnection *connection, - const GError *error, - gpointer list) +tp_contact_list_constructed (GObject *list) { - EmpathyTpContactListPriv *priv = GET_PRIV (list); - if (error) { - tp_contact_list_invalidated_cb (connection, - error->domain, - error->code, - error->message, - EMPATHY_TP_CONTACT_LIST (list)); - return; - } + EmpathyTpContactListPriv *priv = GET_PRIV (list); + gchar *protocol_name = NULL; + const gchar *names[] = {NULL, NULL}; - g_signal_connect (priv->connection, "invalidated", - G_CALLBACK (tp_contact_list_invalidated_cb), - list); + priv->factory = empathy_tp_contact_factory_dup_singleton (priv->connection); - tp_contact_list_request_list (list, "publish"); - tp_contact_list_request_list (list, "subscribe"); + names[0] = "publish"; + tp_cli_connection_call_request_handles (priv->connection, + -1, + TP_HANDLE_TYPE_LIST, + names, + tp_contact_list_publish_request_handle_cb, + NULL, NULL, + G_OBJECT (list)); + names[0] = "subscribe"; + tp_cli_connection_call_request_handles (priv->connection, + -1, + TP_HANDLE_TYPE_LIST, + names, + tp_contact_list_subscribe_request_handle_cb, + NULL, NULL, + G_OBJECT (list)); tp_cli_connection_call_list_channels (priv->connection, -1, tp_contact_list_list_channels_cb, @@ -699,39 +718,15 @@ tp_contact_list_connection_ready (TpConnection *connection, tp_contact_list_new_channel_cb, NULL, NULL, list, NULL); -} - -static void -tp_contact_list_constructed (GObject *list) -{ - - EmpathyTpContactListPriv *priv = GET_PRIV (list); - MissionControl *mc; - guint status; - McProfile *profile; - const gchar *protocol_name; - - /* Get the connection. status==0 means CONNECTED */ - mc = empathy_mission_control_dup_singleton (); - status = mission_control_get_connection_status (mc, priv->account, NULL); - g_return_if_fail (status == 0); - priv->connection = mission_control_get_tpconnection (mc, priv->account, NULL); - g_return_if_fail (priv->connection != NULL); - g_object_unref (mc); - - tp_connection_call_when_ready (priv->connection, - tp_contact_list_connection_ready, - list); /* Check for protocols that does not support contact groups. We can * put all contacts into a special group in that case. * FIXME: Default group should be an information in the profile */ - profile = mc_account_get_profile (priv->account); - protocol_name = mc_profile_get_protocol_name (profile); - if (strcmp (protocol_name, "local-xmpp") == 0) { + tp_connection_parse_object_path (priv->connection, &protocol_name, NULL); + if (!tp_strdiff (protocol_name, "local-xmpp")) { priv->protocol_group = _("People nearby"); } - g_object_unref (profile); + g_free (protocol_name); } static void @@ -743,8 +738,8 @@ tp_contact_list_get_property (GObject *object, EmpathyTpContactListPriv *priv = GET_PRIV (object); switch (param_id) { - case PROP_ACCOUNT: - g_value_set_object (value, priv->account); + case PROP_CONNECTION: + g_value_set_object (value, priv->connection); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -761,8 +756,8 @@ tp_contact_list_set_property (GObject *object, EmpathyTpContactListPriv *priv = GET_PRIV (object); switch (param_id) { - case PROP_ACCOUNT: - priv->account = g_object_ref (g_value_get_object (value)); + case PROP_CONNECTION: + priv->connection = g_value_dup_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -781,27 +776,23 @@ empathy_tp_contact_list_class_init (EmpathyTpContactListClass *klass) object_class->set_property = tp_contact_list_set_property; g_object_class_install_property (object_class, - PROP_ACCOUNT, - g_param_spec_object ("account", - "The Account", - "The account associated with the contact list", - MC_TYPE_ACCOUNT, + PROP_CONNECTION, + g_param_spec_object ("connection", + "The Connection", + "The connection associated with the contact list", + TP_TYPE_CONNECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - signals[DESTROY] = - g_signal_new ("destroy", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - g_type_class_add_private (object_class, sizeof (EmpathyTpContactListPriv)); } +static void +tp_contact_list_array_free (gpointer handles) +{ + g_array_free (handles, TRUE); +} + static void empathy_tp_contact_list_init (EmpathyTpContactList *list) { @@ -809,22 +800,39 @@ empathy_tp_contact_list_init (EmpathyTpContactList *list) EMPATHY_TYPE_TP_CONTACT_LIST, EmpathyTpContactListPriv); list->priv = priv; - priv->contacts_groups = g_hash_table_new_full (g_direct_hash, - g_direct_equal, - (GDestroyNotify) g_object_unref, - (GDestroyNotify) tp_contact_list_group_list_free); + + /* Map group's name to group's TpChannel. The group name string is owned + * by the TpChannel object */ + priv->groups = g_hash_table_new_full (g_str_hash, g_str_equal, + NULL, + (GDestroyNotify) g_object_unref); + + /* Map contact's handle to EmpathyContact object */ + priv->members = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, + (GDestroyNotify) g_object_unref); + + /* Map contact's handle to EmpathyContact object */ + priv->pendings = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, + (GDestroyNotify) g_object_unref); + + /* Map group's name to GArray of handle */ + priv->add_to_group = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, + tp_contact_list_array_free); } EmpathyTpContactList * -empathy_tp_contact_list_new (McAccount *account) +empathy_tp_contact_list_new (TpConnection *connection) { return g_object_new (EMPATHY_TYPE_TP_CONTACT_LIST, - "account", account, + "connection", connection, NULL); } -McAccount * -empathy_tp_contact_list_get_account (EmpathyTpContactList *list) +TpConnection * +empathy_tp_contact_list_get_connection (EmpathyTpContactList *list) { EmpathyTpContactListPriv *priv; @@ -832,7 +840,7 @@ empathy_tp_contact_list_get_account (EmpathyTpContactList *list) priv = GET_PRIV (list); - return priv->account; + return priv->connection; } static void @@ -841,15 +849,18 @@ tp_contact_list_add (EmpathyContactList *list, const gchar *message) { EmpathyTpContactListPriv *priv = GET_PRIV (list); + TpHandle handle; + GArray handles = {(gchar *) &handle, 1}; - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); - + handle = empathy_contact_get_handle (contact); if (priv->subscribe) { - empathy_tp_group_add_member (priv->subscribe, contact, message); + tp_cli_channel_interface_group_call_add_members (priv->subscribe, + -1, &handles, message, NULL, NULL, NULL, NULL); } - - if (priv->publish && g_list_find (priv->pendings, contact)) { - empathy_tp_group_add_member (priv->publish, contact, message); + if (priv->publish && + g_hash_table_lookup (priv->pendings, GUINT_TO_POINTER (handle))) { + tp_cli_channel_interface_group_call_add_members (priv->publish, + -1, &handles, message, NULL, NULL, NULL, NULL); } } @@ -859,14 +870,17 @@ tp_contact_list_remove (EmpathyContactList *list, const gchar *message) { EmpathyTpContactListPriv *priv = GET_PRIV (list); + TpHandle handle; + GArray handles = {(gchar *) &handle, 1}; - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); - + handle = empathy_contact_get_handle (contact); if (priv->subscribe) { - empathy_tp_group_remove_member (priv->subscribe, contact, message); + tp_cli_channel_interface_group_call_remove_members (priv->subscribe, + -1, &handles, message, NULL, NULL, NULL, NULL); } if (priv->publish) { - empathy_tp_group_remove_member (priv->publish, contact, message); + tp_cli_channel_interface_group_call_remove_members (priv->publish, + -1, &handles, message, NULL, NULL, NULL, NULL); } } @@ -874,44 +888,40 @@ static GList * tp_contact_list_get_members (EmpathyContactList *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); + GList *ret; - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); - - g_list_foreach (priv->members, (GFunc) g_object_ref, NULL); - return g_list_copy (priv->members); + ret = g_hash_table_get_values (priv->members); + g_list_foreach (ret, (GFunc) g_object_ref, NULL); + return ret; } static GList * tp_contact_list_get_pendings (EmpathyContactList *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); + GList *ret; - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); - - g_list_foreach (priv->pendings, (GFunc) g_object_ref, NULL); - return g_list_copy (priv->pendings); + ret = g_hash_table_get_values (priv->pendings); + g_list_foreach (ret, (GFunc) g_object_ref, NULL); + return ret; } static GList * tp_contact_list_get_all_groups (EmpathyContactList *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - GList *groups = NULL, *l; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); + GList *ret, *l; - if (priv->protocol_group) { - groups = g_list_prepend (groups, g_strdup (priv->protocol_group)); + ret = g_hash_table_get_keys (priv->groups); + for (l = ret; l; l = l->next) { + l->data = g_strdup (l->data); } - for (l = priv->groups; l; l = l->next) { - const gchar *name; - - name = empathy_tp_group_get_name (l->data); - groups = g_list_prepend (groups, g_strdup (name)); + if (priv->protocol_group) { + ret = g_list_prepend (ret, g_strdup (priv->protocol_group)); } - return groups; + return ret; } static GList * @@ -919,174 +929,119 @@ tp_contact_list_get_groups (EmpathyContactList *list, EmpathyContact *contact) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - GList **groups; - GList *ret = NULL, *l; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); + GList *ret = NULL; + GHashTableIter iter; + gpointer group_name; + gpointer channel; + TpHandle handle; + + handle = empathy_contact_get_handle (contact); + g_hash_table_iter_init (&iter, priv->groups); + while (g_hash_table_iter_next (&iter, &group_name, &channel)) { + const TpIntSet *members; + + members = tp_channel_group_get_members (channel); + if (tp_intset_is_member (members, handle)) { + ret = g_list_prepend (ret, g_strdup (group_name)); + } + } if (priv->protocol_group) { ret = g_list_prepend (ret, g_strdup (priv->protocol_group)); } - groups = g_hash_table_lookup (priv->contacts_groups, contact); - if (!groups) { - return ret; - } - - for (l = *groups; l; l = l->next) { - ret = g_list_prepend (ret, g_strdup (l->data)); - } - - return ret; } -static EmpathyTpGroup * -tp_contact_list_get_group (EmpathyTpContactList *list, - const gchar *group) -{ - EmpathyTpContactListPriv *priv = GET_PRIV (list); - EmpathyTpGroup *tp_group; - gchar *object_path; - guint handle; - GArray *handles; - const char *names[2] = {group, NULL}; - GError *error = NULL; - - tp_group = tp_contact_list_find_group (list, group); - if (tp_group) { - return tp_group; - } - - DEBUG ("creating new group: %s", group); - - if (!tp_cli_connection_run_request_handles (priv->connection, -1, - TP_HANDLE_TYPE_GROUP, - names, - &handles, - &error, NULL)) { - DEBUG ("Failed to RequestHandles: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - return NULL; - } - handle = g_array_index (handles, guint, 0); - g_array_free (handles, TRUE); - - if (!tp_cli_connection_run_request_channel (priv->connection, -1, - TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, - TP_HANDLE_TYPE_GROUP, - handle, - TRUE, - &object_path, - &error, NULL)) { - DEBUG ("Failed to RequestChannel: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - return NULL; - } - - tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list), - object_path, - TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, - TP_HANDLE_TYPE_GROUP, handle); - - g_free (object_path); - - return tp_contact_list_find_group (list, group); -} - static void tp_contact_list_add_to_group (EmpathyContactList *list, EmpathyContact *contact, - const gchar *group) + const gchar *group_name) { - EmpathyTpGroup *tp_group; - - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); - - tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list), - group); - - if (tp_group) { - empathy_tp_group_add_member (tp_group, contact, ""); - } + TpHandle handle; + GArray *handles; + + handle = empathy_contact_get_handle (contact); + handles = g_array_sized_new (FALSE, FALSE, sizeof (TpHandle), 1); + g_array_append_val (handles, handle); + tp_contact_list_group_add (EMPATHY_TP_CONTACT_LIST (list), + group_name, handles); } static void tp_contact_list_remove_from_group (EmpathyContactList *list, EmpathyContact *contact, - const gchar *group) + const gchar *group_name) { - EmpathyTpGroup *tp_group; + EmpathyTpContactListPriv *priv = GET_PRIV (list); + TpChannel *channel; + TpHandle handle; + GArray handles = {(gchar *) &handle, 1}; - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); + channel = g_hash_table_lookup (priv->groups, group_name); + if (channel == NULL) { + return; + } - tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list), - group); + handle = empathy_contact_get_handle (contact); + DEBUG ("remove contact %s (%d) from group %s", + empathy_contact_get_id (contact), handle, group_name); - if (tp_group) { - empathy_tp_group_remove_member (tp_group, contact, ""); - } + tp_cli_channel_interface_group_call_remove_members (channel, -1, + &handles, NULL, NULL, NULL, NULL, NULL); } static void tp_contact_list_rename_group (EmpathyContactList *list, - const gchar *old_group, - const gchar *new_group) + const gchar *old_group_name, + const gchar *new_group_name) { - EmpathyTpGroup *tp_group; - GList *members; - - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); + EmpathyTpContactListPriv *priv = GET_PRIV (list); + TpChannel *channel; + const TpIntSet *members; + GArray *handles; - tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list), - old_group); - if (!tp_group) { + channel = g_hash_table_lookup (priv->groups, old_group_name); + if (channel == NULL) { return; } - DEBUG ("rename group %s to %s", old_group, new_group); - - /* Remove all members from the old group */ - members = empathy_tp_group_get_members (tp_group); - empathy_tp_group_remove_members (tp_group, members, ""); - empathy_tp_group_close (tp_group); + DEBUG ("rename group %s to %s", old_group_name, new_group_name); - /* Add all members to the new group */ - tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list), - new_group); - empathy_tp_group_add_members (tp_group, members, ""); + /* Remove all members and close the old channel */ + members = tp_channel_group_get_members (channel); + handles = tp_intset_to_array (members); + tp_cli_channel_interface_group_call_remove_members (channel, -1, + handles, NULL, NULL, NULL, NULL, NULL); + tp_cli_channel_call_close (channel, -1, NULL, NULL, NULL, NULL); - g_list_foreach (members, (GFunc) g_object_unref, NULL); - g_list_free (members); + tp_contact_list_group_add (EMPATHY_TP_CONTACT_LIST (list), + new_group_name, handles); } static void tp_contact_list_remove_group (EmpathyContactList *list, - const gchar *group) + const gchar *group_name) { - EmpathyTpGroup *tp_group; - GList *members; - - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); + EmpathyTpContactListPriv *priv = GET_PRIV (list); + TpChannel *channel; + const TpIntSet *members; + GArray *handles; - tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list), - group); - - if (!tp_group) { + channel = g_hash_table_lookup (priv->groups, group_name); + if (channel == NULL) { return; } - DEBUG ("remove group %s", group); + DEBUG ("remove group %s", group_name); - /* Remove all members of the group */ - members = empathy_tp_group_get_members (tp_group); - empathy_tp_group_remove_members (tp_group, members, ""); - empathy_tp_group_close (tp_group); - - g_list_foreach (members, (GFunc) g_object_unref, NULL); - g_list_free (members); + /* Remove all members and close the channel */ + members = tp_channel_group_get_members (channel); + handles = tp_intset_to_array (members); + tp_cli_channel_interface_group_call_remove_members (channel, -1, + handles, NULL, NULL, NULL, NULL, NULL); + tp_cli_channel_call_close (channel, -1, NULL, NULL, NULL, NULL); + g_array_free (handles, TRUE); } static void @@ -1117,6 +1072,34 @@ empathy_tp_contact_list_can_add (EmpathyTpContactList *list) if (priv->subscribe == NULL) return FALSE; - flags = empathy_tp_group_get_flags (priv->subscribe); + flags = tp_channel_group_get_flags (priv->subscribe); return (flags & TP_CHANNEL_GROUP_FLAG_CAN_ADD) != 0; } + +void +empathy_tp_contact_list_remove_all (EmpathyTpContactList *list) +{ + EmpathyTpContactListPriv *priv = GET_PRIV (list); + GHashTableIter iter; + gpointer contact; + + g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); + + /* Remove all contacts */ + g_hash_table_iter_init (&iter, priv->members); + while (g_hash_table_iter_next (&iter, NULL, &contact)) { + g_signal_emit_by_name (list, "members-changed", contact, + NULL, 0, NULL, + FALSE); + } + g_hash_table_remove_all (priv->members); + + g_hash_table_iter_init (&iter, priv->pendings); + while (g_hash_table_iter_next (&iter, NULL, &contact)) { + g_signal_emit_by_name (list, "pendings-changed", contact, + NULL, 0, NULL, + FALSE); + } + g_hash_table_remove_all (priv->pendings); +} + diff --git a/libempathy/empathy-tp-contact-list.h b/libempathy/empathy-tp-contact-list.h index e8edcfac..c6cf6cb4 100644 --- a/libempathy/empathy-tp-contact-list.h +++ b/libempathy/empathy-tp-contact-list.h @@ -24,7 +24,7 @@ #define __EMPATHY_TP_CONTACT_LIST_H__ #include -#include +#include G_BEGIN_DECLS @@ -49,9 +49,10 @@ struct _EmpathyTpContactListClass { }; GType empathy_tp_contact_list_get_type (void) G_GNUC_CONST; -EmpathyTpContactList * empathy_tp_contact_list_new (McAccount *account); -McAccount * empathy_tp_contact_list_get_account (EmpathyTpContactList *list); +EmpathyTpContactList * empathy_tp_contact_list_new (TpConnection *connection); +TpConnection * empathy_tp_contact_list_get_connection (EmpathyTpContactList *list); gboolean empathy_tp_contact_list_can_add (EmpathyTpContactList *list); +void empathy_tp_contact_list_remove_all (EmpathyTpContactList *list); G_END_DECLS diff --git a/libempathy/empathy-tp-file.c b/libempathy/empathy-tp-file.c index 1f6bedfb..6796f5a0 100644 --- a/libempathy/empathy-tp-file.c +++ b/libempathy/empathy-tp-file.c @@ -39,7 +39,7 @@ #include #include "empathy-tp-file.h" -#include "empathy-contact-factory.h" +#include "empathy-tp-contact-factory.h" #include "empathy-marshal.h" #include "empathy-time.h" #include "empathy-utils.h" @@ -277,9 +277,10 @@ copy_stream (GInputStream *in, /* EmpathyTpFile object */ struct _EmpathyTpFilePriv { - EmpathyContactFactory *factory; + EmpathyTpContactFactory *factory; MissionControl *mc; TpChannel *channel; + gboolean ready; EmpathyContact *contact; GInputStream *in_stream; @@ -307,6 +308,7 @@ enum { PROP_CHANNEL, PROP_STATE, PROP_INCOMING, + PROP_READY, PROP_FILENAME, PROP_SIZE, PROP_CONTENT_TYPE, @@ -493,81 +495,154 @@ tp_file_transferred_bytes_changed_cb (TpChannel *channel, g_object_notify (G_OBJECT (tp_file), "transferred-bytes"); } -static GObject * -tp_file_constructor (GType type, - guint n_props, - GObjectConstructParam *props) +static void +tp_file_check_if_ready (EmpathyTpFile *tp_file) { - GObject *file_obj; - EmpathyTpFile *tp_file; - TpHandle handle; - GHashTable *properties; - McAccount *account; - GValue *requested; - - file_obj = G_OBJECT_CLASS (empathy_tp_file_parent_class)->constructor (type, - n_props, props); - - tp_file = EMPATHY_TP_FILE (file_obj); - - tp_file->priv->factory = empathy_contact_factory_dup_singleton (); - tp_file->priv->mc = empathy_mission_control_dup_singleton (); - - g_signal_connect (tp_file->priv->channel, "invalidated", - G_CALLBACK (tp_file_invalidated_cb), tp_file); + if (tp_file->priv->ready || tp_file->priv->contact == NULL || + tp_file->priv->state == 0) + return; - tp_cli_channel_type_file_transfer_connect_to_file_transfer_state_changed ( - tp_file->priv->channel, tp_file_state_changed_cb, NULL, NULL, - G_OBJECT (tp_file), NULL); + tp_file->priv->ready = TRUE; + g_object_notify (G_OBJECT (tp_file), "ready"); +} - tp_cli_channel_type_file_transfer_connect_to_transferred_bytes_changed ( - tp_file->priv->channel, tp_file_transferred_bytes_changed_cb, - NULL, NULL, G_OBJECT (tp_file), NULL); +static void +tp_file_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + EmpathyTpFile *tp_file = EMPATHY_TP_FILE (weak_object); - account = empathy_channel_get_account (tp_file->priv->channel); + if (error) + { + DEBUG ("Error: %s", error->message); + empathy_tp_file_close (tp_file); + return; + } - handle = tp_channel_get_handle (tp_file->priv->channel, NULL); - tp_file->priv->contact = empathy_contact_factory_get_from_handle ( - tp_file->priv->factory, account, (guint) handle); + tp_file->priv->contact = g_object_ref (contact); + tp_file_check_if_ready (tp_file); +} - tp_cli_dbus_properties_run_get_all (tp_file->priv->channel, - -1, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, &properties, NULL, NULL); +static void +tp_file_get_all_cb (TpProxy *proxy, + GHashTable *properties, + const GError *error, + gpointer user_data, + GObject *file_obj) +{ + EmpathyTpFile *tp_file = EMPATHY_TP_FILE (file_obj); - tp_cli_dbus_properties_run_get (tp_file->priv->channel, - -1, TP_IFACE_CHANNEL, "Requested", &requested, NULL, NULL); + if (error) + { + DEBUG ("Error: %s", error->message); + tp_cli_channel_call_close (tp_file->priv->channel, -1, NULL, NULL, NULL, + NULL); + return; + } tp_file->priv->size = g_value_get_uint64 ( g_hash_table_lookup (properties, "Size")); + g_object_notify (file_obj, "size"); tp_file->priv->state = g_value_get_uint ( g_hash_table_lookup (properties, "State")); - - tp_file->priv->state_change_reason = - TP_FILE_TRANSFER_STATE_CHANGE_REASON_NONE; + g_object_notify (file_obj, "state"); tp_file->priv->transferred_bytes = g_value_get_uint64 ( g_hash_table_lookup (properties, "TransferredBytes")); + g_object_notify (file_obj, "transferred-bytes"); tp_file->priv->filename = g_value_dup_string ( g_hash_table_lookup (properties, "Filename")); + g_object_notify (file_obj, "filename"); tp_file->priv->content_hash = g_value_dup_string ( g_hash_table_lookup (properties, "ContentHash")); + g_object_notify (file_obj, "content-hash"); tp_file->priv->content_hash_type = g_value_get_uint ( g_hash_table_lookup (properties, "ContentHashType")); + g_object_notify (file_obj, "content-hash-type"); tp_file->priv->content_type = g_value_dup_string ( g_hash_table_lookup (properties, "ContentType")); + g_object_notify (file_obj, "content-type"); tp_file->priv->description = g_value_dup_string ( g_hash_table_lookup (properties, "Description")); + tp_file_check_if_ready (tp_file); +} + +static void +tp_file_get_requested_cb (TpProxy *proxy, + const GValue *requested, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + EmpathyTpFile *tp_file = EMPATHY_TP_FILE (weak_object); + + if (error) + { + DEBUG ("Error: %s", error->message); + tp_cli_channel_call_close (tp_file->priv->channel, -1, NULL, NULL, NULL, + NULL); + return; + } + tp_file->priv->incoming = !g_value_get_boolean (requested); + g_object_notify (G_OBJECT (tp_file), "incoming"); + + tp_file_check_if_ready (tp_file); +} + +static GObject * +tp_file_constructor (GType type, + guint n_props, + GObjectConstructParam *props) +{ + GObject *file_obj; + EmpathyTpFile *tp_file; + TpHandle handle; + TpConnection *connection; + + file_obj = G_OBJECT_CLASS (empathy_tp_file_parent_class)->constructor (type, + n_props, props); + + tp_file = EMPATHY_TP_FILE (file_obj); + + connection = tp_channel_borrow_connection (tp_file->priv->channel); + tp_file->priv->factory = empathy_tp_contact_factory_dup_singleton (connection); + tp_file->priv->mc = empathy_mission_control_dup_singleton (); + tp_file->priv->state_change_reason = + TP_FILE_TRANSFER_STATE_CHANGE_REASON_NONE; + + g_signal_connect (tp_file->priv->channel, "invalidated", + G_CALLBACK (tp_file_invalidated_cb), tp_file); + + tp_cli_channel_type_file_transfer_connect_to_file_transfer_state_changed ( + tp_file->priv->channel, tp_file_state_changed_cb, NULL, NULL, + G_OBJECT (tp_file), NULL); + + tp_cli_channel_type_file_transfer_connect_to_transferred_bytes_changed ( + tp_file->priv->channel, tp_file_transferred_bytes_changed_cb, + NULL, NULL, G_OBJECT (tp_file), NULL); - g_hash_table_destroy (properties); - g_object_unref (account); - g_value_unset (requested); + tp_cli_dbus_properties_call_get (tp_file->priv->channel, -1, + TP_IFACE_CHANNEL, "Requested", + tp_file_get_requested_cb, NULL, NULL, file_obj); + + tp_cli_dbus_properties_call_get_all (tp_file->priv->channel, -1, + TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, + tp_file_get_all_cb, NULL, NULL, file_obj); + + handle = tp_channel_get_handle (tp_file->priv->channel, NULL); + empathy_tp_contact_factory_get_from_handle (tp_file->priv->factory, + handle, tp_file_got_contact_cb, NULL, NULL, file_obj); return file_obj; } @@ -611,6 +686,9 @@ tp_file_get_property (GObject *object, case PROP_TRANSFERRED_BYTES: g_value_set_uint64 (value, tp_file->priv->transferred_bytes); break; + case PROP_READY: + g_value_set_boolean (value, tp_file->priv->ready); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; @@ -956,6 +1034,14 @@ empathy_tp_file_close (EmpathyTpFile *tp_file) empathy_tp_file_cancel (tp_file); } +gboolean +empathy_tp_file_is_ready (EmpathyTpFile *tp_file) +{ + g_return_val_if_fail (EMPATHY_IS_TP_FILE (tp_file), FALSE); + + return tp_file->priv->ready; +} + static void empathy_tp_file_class_init (EmpathyTpFileClass *klass) { @@ -996,6 +1082,14 @@ empathy_tp_file_class_init (EmpathyTpFileClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + g_object_class_install_property (object_class, + PROP_READY, + g_param_spec_boolean ("ready", + "ready", + "Whether the object is ready", + FALSE, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, PROP_FILENAME, g_param_spec_string ("filename", diff --git a/libempathy/empathy-tp-file.h b/libempathy/empathy-tp-file.h index 42c54e4f..5f239c8e 100644 --- a/libempathy/empathy-tp-file.h +++ b/libempathy/empathy-tp-file.h @@ -81,6 +81,7 @@ guint64 empathy_tp_file_get_size (EmpathyTpFile *tp_file); guint64 empathy_tp_file_get_transferred_bytes (EmpathyTpFile *tp_file); gint empathy_tp_file_get_remaining_time (EmpathyTpFile *tp_file); const gchar *empathy_tp_file_get_content_type (EmpathyTpFile *tp_file); +gboolean empathy_tp_file_is_ready (EmpathyTpFile *tp_file); G_END_DECLS diff --git a/libempathy/empathy-tp-group.c b/libempathy/empathy-tp-group.c deleted file mode 100644 index c3471c15..00000000 --- a/libempathy/empathy-tp-group.c +++ /dev/null @@ -1,981 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006 Xavier Claessens - * Copyright (C) 2007-2008 Collabora Ltd. - * - * This library 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.1 of the License, or (at your option) any later version. - * - * This library 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 library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Authors: Xavier Claessens - */ - -#include - -#include - -#include -#include - -#include "empathy-tp-group.h" -#include "empathy-contact-factory.h" -#include "empathy-utils.h" -#include "empathy-marshal.h" - -#define DEBUG_FLAG EMPATHY_DEBUG_TP -#include "empathy-debug.h" - -#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyTpGroup) -typedef struct { - TpChannel *channel; - gboolean ready; - - EmpathyContactFactory *factory; - McAccount *account; - gchar *group_name; - guint self_handle; - GList *members; - GList *local_pendings; - GList *remote_pendings; -} EmpathyTpGroupPriv; - -enum { - MEMBER_ADDED, - MEMBER_REMOVED, - LOCAL_PENDING, - REMOTE_PENDING, - DESTROY, - LAST_SIGNAL -}; - -enum { - PROP_0, - PROP_CHANNEL, - PROP_READY -}; - -static guint signals[LAST_SIGNAL]; - -G_DEFINE_TYPE (EmpathyTpGroup, empathy_tp_group, G_TYPE_OBJECT); - -static EmpathyContact * -tp_group_get_contact (EmpathyTpGroup *group, - guint handle) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - EmpathyContact *contact = NULL; - - if (handle != 0) { - contact = empathy_contact_factory_get_from_handle (priv->factory, - priv->account, - handle); - } - - if (contact && handle == priv->self_handle) { - empathy_contact_set_is_user (contact, TRUE); - } - - return contact; -} - -static GList * -tp_group_get_contacts (EmpathyTpGroup *group, - const GArray *handles) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - GList *contacts, *l; - - if (!handles) { - return NULL; - } - - contacts = empathy_contact_factory_get_from_handles (priv->factory, - priv->account, - handles); - - /* FIXME: Only useful if the group has a different self handle than - * the connection, otherwise the contact factory already set that - * property. That can be known using group flags. */ - for (l = contacts; l; l = l->next) { - if (empathy_contact_get_handle (l->data) == priv->self_handle) { - empathy_contact_set_is_user (l->data, TRUE); - } - } - - return contacts; -} - -EmpathyPendingInfo * -empathy_pending_info_new (EmpathyContact *member, - EmpathyContact *actor, - const gchar *message) -{ - EmpathyPendingInfo *info; - - info = g_slice_new0 (EmpathyPendingInfo); - - if (member) { - info->member = g_object_ref (member); - } - if (actor) { - info->actor = g_object_ref (actor); - } - if (message) { - info->message = g_strdup (message); - } - - return info; -} - -void -empathy_pending_info_free (EmpathyPendingInfo *info) -{ - if (!info) { - return; - } - - if (info->member) { - g_object_unref (info->member); - } - if (info->actor) { - g_object_unref (info->actor); - } - g_free (info->message); - - g_slice_free (EmpathyPendingInfo, info); -} - -static gint -tp_group_local_pending_find (gconstpointer a, - gconstpointer b) -{ - const EmpathyPendingInfo *info = a; - - return (info->member != b); -} - -static void -tp_group_remove_from_pendings (EmpathyTpGroup *group, - EmpathyContact *contact) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - GList *l; - - /* local pending */ - l = g_list_find_custom (priv->local_pendings, - contact, - tp_group_local_pending_find); - if (l) { - empathy_pending_info_free (l->data); - priv->local_pendings = g_list_delete_link (priv->local_pendings, l); - } - - /* remote pending */ - l = g_list_find (priv->remote_pendings, contact); - if (l) { - g_object_unref (l->data); - priv->remote_pendings = g_list_delete_link (priv->remote_pendings, l); - } -} - -static void -tp_group_update_members (EmpathyTpGroup *group, - const gchar *message, - const GArray *added, - const GArray *removed, - const GArray *local_pending, - const GArray *remote_pending, - guint actor, - guint reason) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - EmpathyContact *actor_contact = NULL; - GList *contacts, *l, *ll; - - actor_contact = tp_group_get_contact (group, actor); - - DEBUG ("Members changed for list %s:\n" - " added-len=%d, current-len=%d\n" - " removed-len=%d\n" - " local-pending-len=%d, current-len=%d\n" - " remote-pending-len=%d, current-len=%d", - priv->group_name, added ? added->len : 0, - g_list_length (priv->members), removed ? removed->len : 0, - local_pending ? local_pending->len : 0, - g_list_length (priv->local_pendings), - remote_pending ? remote_pending->len : 0, - g_list_length (priv->remote_pendings)); - - /* Contacts added */ - contacts = tp_group_get_contacts (group, added); - for (l = contacts; l; l = l->next) { - tp_group_remove_from_pendings (group, l->data); - - /* If the contact is not yet member, add it and emit signal */ - if (!g_list_find (priv->members, l->data)) { - priv->members = g_list_prepend (priv->members, - g_object_ref (l->data)); - g_signal_emit (group, signals[MEMBER_ADDED], 0, - l->data, actor_contact, reason, message); - } - g_object_unref (l->data); - } - g_list_free (contacts); - - /* Contacts removed */ - contacts = tp_group_get_contacts (group, removed); - for (l = contacts; l; l = l->next) { - tp_group_remove_from_pendings (group, l->data); - - /* If the contact is member, remove it and emit signal */ - if ((ll = g_list_find (priv->members, l->data))) { - g_object_unref (ll->data); - priv->members = g_list_delete_link (priv->members, ll); - g_signal_emit (group, signals[MEMBER_REMOVED], 0, - l->data, actor_contact, reason, message); - } - g_object_unref (l->data); - } - g_list_free (contacts); - - /* Contacts local pending */ - contacts = tp_group_get_contacts (group, local_pending); - for (l = contacts; l; l = l->next) { - /* If the contact is not yet local-pending, add it and emit signal */ - if (!g_list_find_custom (priv->local_pendings, l->data, - tp_group_local_pending_find)) { - EmpathyPendingInfo *info; - - info = empathy_pending_info_new (l->data, - actor_contact, - message); - - priv->local_pendings = g_list_prepend (priv->local_pendings, info); - g_signal_emit (group, signals[LOCAL_PENDING], 0, - l->data, actor_contact, reason, message); - } - g_object_unref (l->data); - } - g_list_free (contacts); - - /* Contacts remote pending */ - contacts = tp_group_get_contacts (group, remote_pending); - for (l = contacts; l; l = l->next) { - /* If the contact is not yet remote-pending, add it and emit signal */ - if (!g_list_find (priv->remote_pendings, l->data)) { - priv->remote_pendings = g_list_prepend (priv->remote_pendings, - g_object_ref (l->data)); - g_signal_emit (group, signals[REMOTE_PENDING], 0, - l->data, actor_contact, reason, message); - } - g_object_unref (l->data); - } - g_list_free (contacts); - - if (actor_contact) { - g_object_unref (actor_contact); - } - - DEBUG ("Members changed done for list %s:\n" - " members-len=%d\n" - " local-pendings-len=%d\n" - " remote-pendings-len=%d", - priv->group_name, g_list_length (priv->members), - g_list_length (priv->local_pendings), - g_list_length (priv->remote_pendings)); -} - -static void -tp_group_members_changed_cb (TpChannel *channel, - const gchar *message, - const GArray *added, - const GArray *removed, - const GArray *local_pending, - const GArray *remote_pending, - guint actor, - guint reason, - gpointer user_data, - GObject *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - if (priv->ready) { - tp_group_update_members (EMPATHY_TP_GROUP (group), message, - added, removed, - local_pending, remote_pending, - actor, reason); - } -} - -static void -tp_group_get_members_cb (TpChannel *channel, - const GArray *handles, - const GError *error, - gpointer user_data, - GObject *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - if (error) { - DEBUG ("Failed to get members: %s", error->message); - return; - } - - tp_group_update_members (EMPATHY_TP_GROUP (group), - NULL, /* message */ - handles, /* added */ - NULL, /* removed */ - NULL, /* local_pending */ - NULL, /* remote_pending */ - 0, /* actor */ - 0); /* reason */ - - DEBUG ("Ready"); - priv->ready = TRUE; - g_object_notify (group, "ready"); -} - -static void -tp_group_get_local_pending_cb (TpChannel *channel, - const GPtrArray *array, - const GError *error, - gpointer user_data, - GObject *group) -{ - GArray *handles; - guint i = 0; - - if (error) { - DEBUG ("Failed to get local pendings: %s", error->message); - return; - } - - handles = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1); - g_array_append_val (handles, i); - for (i = 0; array->len > i; i++) { - GValueArray *pending_struct; - const gchar *message; - guint member_handle; - guint actor_handle; - guint reason; - - pending_struct = g_ptr_array_index (array, i); - member_handle = g_value_get_uint (g_value_array_get_nth (pending_struct, 0)); - actor_handle = g_value_get_uint (g_value_array_get_nth (pending_struct, 1)); - reason = g_value_get_uint (g_value_array_get_nth (pending_struct, 2)); - message = g_value_get_string (g_value_array_get_nth (pending_struct, 3)); - - g_array_index (handles, guint, 0) = member_handle; - - tp_group_update_members (EMPATHY_TP_GROUP (group), - message, /* message */ - NULL, /* added */ - NULL, /* removed */ - handles, /* local_pending */ - NULL, /* remote_pending */ - actor_handle, /* actor */ - reason); /* reason */ - } - g_array_free (handles, TRUE); -} - -static void -tp_group_get_remote_pending_cb (TpChannel *channel, - const GArray *handles, - const GError *error, - gpointer user_data, - GObject *group) -{ - if (error) { - DEBUG ("Failed to get remote pendings: %s", error->message); - return; - } - - tp_group_update_members (EMPATHY_TP_GROUP (group), - NULL, /* message */ - NULL, /* added */ - NULL, /* removed */ - NULL, /* local_pending */ - handles, /* remote_pending */ - 0, /* actor */ - 0); /* reason */ -} - -static void -tp_group_inspect_handles_cb (TpConnection *connection, - const gchar **names, - const GError *error, - gpointer user_data, - GObject *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - if (error) { - DEBUG ("Failed to inspect channel handle: %s", error->message); - return; - } - - priv->group_name = g_strdup (*names); -} - -static void -tp_group_invalidated_cb (TpProxy *proxy, - guint domain, - gint code, - gchar *message, - EmpathyTpGroup *group) -{ - DEBUG ("Channel invalidated: %s", message); - g_signal_emit (group, signals[DESTROY], 0); -} - -static void -tp_group_get_self_handle_cb (TpChannel *proxy, - guint handle, - const GError *error, - gpointer user_data, - GObject *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - TpConnection *connection; - guint channel_handle; - guint channel_handle_type; - GArray *handles; - - if (error) { - DEBUG ("Failed to get self handle: %s", error->message); - return; - } - - priv->self_handle = handle; - tp_cli_channel_interface_group_connect_to_members_changed (priv->channel, - tp_group_members_changed_cb, - NULL, NULL, - group, NULL); - - /* GetMembers is called last, so it will be the last to get the reply, - * so we'll be ready once that call return. */ - g_object_get (priv->channel, - "connection", &connection, - "handle-type", &channel_handle_type, - "handle", &channel_handle, - NULL); - handles = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1); - g_array_prepend_val (handles, channel_handle); - tp_cli_connection_call_inspect_handles (connection, -1, - channel_handle_type, - handles, - tp_group_inspect_handles_cb, - NULL, NULL, - group); - g_array_free (handles, TRUE); - - tp_cli_channel_interface_group_call_get_local_pending_members_with_info - (priv->channel, -1, - tp_group_get_local_pending_cb, - NULL, NULL, - group); - tp_cli_channel_interface_group_call_get_remote_pending_members - (priv->channel, -1, - tp_group_get_remote_pending_cb, - NULL, NULL, - group); - tp_cli_channel_interface_group_call_get_members (priv->channel, -1, - tp_group_get_members_cb, - NULL, NULL, - group); -} - -static void -tp_group_factory_ready_cb (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - EmpathyTpContactFactory *tp_factory; - - tp_factory = empathy_contact_factory_get_tp_factory (priv->factory, priv->account); - g_signal_handlers_disconnect_by_func (tp_factory, tp_group_factory_ready_cb, group); - tp_cli_channel_interface_group_call_get_self_handle (priv->channel, -1, - tp_group_get_self_handle_cb, - NULL, NULL, - G_OBJECT (group)); -} - -static void -tp_group_channel_ready_cb (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - EmpathyTpContactFactory *tp_factory; - - tp_factory = empathy_contact_factory_get_tp_factory (priv->factory, - priv->account); - if (empathy_tp_contact_factory_is_ready (tp_factory)) { - tp_group_factory_ready_cb (group); - } else { - g_signal_connect_swapped (tp_factory, "notify::ready", - G_CALLBACK (tp_group_factory_ready_cb), - group); - } -} - -static void -tp_group_finalize (GObject *object) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (object); - EmpathyTpContactFactory *tp_factory; - - DEBUG ("finalize: %p", object); - - tp_factory = empathy_contact_factory_get_tp_factory (priv->factory, priv->account); - g_signal_handlers_disconnect_by_func (tp_factory, tp_group_factory_ready_cb, object); - - if (priv->channel) { - g_signal_handlers_disconnect_by_func (priv->channel, - tp_group_invalidated_cb, - object); - g_object_unref (priv->channel); - } - if (priv->account) { - g_object_unref (priv->account); - } - if (priv->factory) { - g_object_unref (priv->factory); - } - g_free (priv->group_name); - - g_list_foreach (priv->members, (GFunc) g_object_unref, NULL); - g_list_free (priv->members); - - g_list_foreach (priv->local_pendings, (GFunc) empathy_pending_info_free, NULL); - g_list_free (priv->local_pendings); - - g_list_foreach (priv->remote_pendings, (GFunc) g_object_unref, NULL); - g_list_free (priv->remote_pendings); - - G_OBJECT_CLASS (empathy_tp_group_parent_class)->finalize (object); -} - -static void -tp_group_constructed (GObject *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - gboolean channel_ready; - - priv->factory = empathy_contact_factory_dup_singleton (); - priv->account = empathy_channel_get_account (priv->channel); - - g_signal_connect (priv->channel, "invalidated", - G_CALLBACK (tp_group_invalidated_cb), - group); - - g_object_get (priv->channel, "channel-ready", &channel_ready, NULL); - if (channel_ready) { - tp_group_channel_ready_cb (EMPATHY_TP_GROUP (group)); - } else { - g_signal_connect_swapped (priv->channel, "notify::channel-ready", - G_CALLBACK (tp_group_channel_ready_cb), - group); - } -} - -static void -tp_group_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (object); - - switch (param_id) { - case PROP_CHANNEL: - g_value_set_object (value, priv->channel); - break; - case PROP_READY: - g_value_set_boolean (value, priv->ready); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - }; -} - -static void -tp_group_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (object); - - switch (param_id) { - case PROP_CHANNEL: - priv->channel = g_object_ref (g_value_get_object (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - }; -} - -static void -empathy_tp_group_class_init (EmpathyTpGroupClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = tp_group_finalize; - object_class->constructed = tp_group_constructed; - object_class->get_property = tp_group_get_property; - object_class->set_property = tp_group_set_property; - - g_object_class_install_property (object_class, - PROP_CHANNEL, - g_param_spec_object ("channel", - "telepathy channel", - "The channel for the group", - TP_TYPE_CHANNEL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY)); - g_object_class_install_property (object_class, - PROP_READY, - g_param_spec_boolean ("ready", - "Is the object ready", - "This object can't be used until this becomes true", - FALSE, - G_PARAM_READABLE)); - - signals[MEMBER_ADDED] = - g_signal_new ("member-added", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - _empathy_marshal_VOID__OBJECT_OBJECT_UINT_STRING, - G_TYPE_NONE, - 4, EMPATHY_TYPE_CONTACT, EMPATHY_TYPE_CONTACT, G_TYPE_UINT, G_TYPE_STRING); - - signals[MEMBER_REMOVED] = - g_signal_new ("member-removed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - _empathy_marshal_VOID__OBJECT_OBJECT_UINT_STRING, - G_TYPE_NONE, - 4, EMPATHY_TYPE_CONTACT, EMPATHY_TYPE_CONTACT, G_TYPE_UINT, G_TYPE_STRING); - - signals[LOCAL_PENDING] = - g_signal_new ("local-pending", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - _empathy_marshal_VOID__OBJECT_OBJECT_UINT_STRING, - G_TYPE_NONE, - 4, EMPATHY_TYPE_CONTACT, EMPATHY_TYPE_CONTACT, G_TYPE_UINT, G_TYPE_STRING); - - signals[REMOTE_PENDING] = - g_signal_new ("remote-pending", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - _empathy_marshal_VOID__OBJECT_OBJECT_UINT_STRING, - G_TYPE_NONE, - 4, EMPATHY_TYPE_CONTACT, EMPATHY_TYPE_CONTACT, G_TYPE_UINT, G_TYPE_STRING); - - signals[DESTROY] = - g_signal_new ("destroy", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - g_type_class_add_private (object_class, sizeof (EmpathyTpGroupPriv)); -} - -static void -empathy_tp_group_init (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (group, - EMPATHY_TYPE_TP_GROUP, EmpathyTpGroupPriv); - - group->priv = priv; -} - -EmpathyTpGroup * -empathy_tp_group_new (TpChannel *channel) -{ - g_return_val_if_fail (TP_IS_CHANNEL (channel), NULL); - - return g_object_new (EMPATHY_TYPE_TP_GROUP, - "channel", channel, - NULL); -} - -static void -tp_group_async_cb (TpChannel *channel, - const GError *error, - gpointer user_data, - GObject *weak_object) -{ - if (error) { - DEBUG ("%s: %s", (gchar*) user_data, error->message); - } -} - -void -empathy_tp_group_close (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - g_return_if_fail (EMPATHY_IS_TP_GROUP (group)); - g_return_if_fail (priv->ready); - - tp_cli_channel_call_close (priv->channel, -1, - tp_group_async_cb, - "Failed to close", NULL, - G_OBJECT (group)); -} - -static GArray * -tp_group_get_handles (GList *contacts) -{ - GArray *handles; - guint length; - GList *l; - - length = g_list_length (contacts); - handles = g_array_sized_new (FALSE, FALSE, sizeof (guint), length); - - for (l = contacts; l; l = l->next) { - guint handle; - - handle = empathy_contact_get_handle (l->data); - g_array_append_val (handles, handle); - } - - return handles; -} - -void -empathy_tp_group_add_members (EmpathyTpGroup *group, - GList *contacts, - const gchar *message) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - GArray *handles; - - g_return_if_fail (EMPATHY_IS_TP_GROUP (group)); - g_return_if_fail (contacts != NULL); - g_return_if_fail (priv->ready); - - handles = tp_group_get_handles (contacts); - tp_cli_channel_interface_group_call_add_members (priv->channel, -1, - handles, - message, - tp_group_async_cb, - "Failed to add members", NULL, - G_OBJECT (group)); - g_array_free (handles, TRUE); -} - -void -empathy_tp_group_remove_members (EmpathyTpGroup *group, - GList *contacts, - const gchar *message) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - GArray *handles; - - g_return_if_fail (EMPATHY_IS_TP_GROUP (group)); - g_return_if_fail (contacts != NULL); - g_return_if_fail (priv->ready); - - handles = tp_group_get_handles (contacts); - tp_cli_channel_interface_group_call_remove_members (priv->channel, -1, - handles, - message, - tp_group_async_cb, - "Failed to remove members", NULL, - G_OBJECT (group)); - g_array_free (handles, TRUE); -} - -void -empathy_tp_group_add_member (EmpathyTpGroup *group, - EmpathyContact *contact, - const gchar *message) -{ - GList *contacts; - - contacts = g_list_prepend (NULL, contact); - empathy_tp_group_add_members (group, contacts, message); - g_list_free (contacts); -} - -void -empathy_tp_group_remove_member (EmpathyTpGroup *group, - EmpathyContact *contact, - const gchar *message) -{ - GList *contacts; - - contacts = g_list_prepend (NULL, contact); - empathy_tp_group_remove_members (group, contacts, message); - g_list_free (contacts); -} - -GList * -empathy_tp_group_get_members (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL); - - g_list_foreach (priv->members, (GFunc) g_object_ref, NULL); - - return g_list_copy (priv->members); -} - -GList * -empathy_tp_group_get_local_pendings (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - GList *pendings = NULL, *l; - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL); - - for (l = priv->local_pendings; l; l = l->next) { - EmpathyPendingInfo *info; - EmpathyPendingInfo *new_info; - - info = l->data; - new_info = empathy_pending_info_new (info->member, - info->actor, - info->message); - pendings = g_list_prepend (pendings, new_info); - } - - return pendings; -} - -GList * -empathy_tp_group_get_remote_pendings (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL); - - g_list_foreach (priv->remote_pendings, (GFunc) g_object_ref, NULL); - - return g_list_copy (priv->remote_pendings); -} - -const gchar * -empathy_tp_group_get_name (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL); - g_return_val_if_fail (priv->ready, NULL); - - return priv->group_name; -} - -EmpathyContact * -empathy_tp_group_get_self_contact (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL); - g_return_val_if_fail (priv->ready, NULL); - - return tp_group_get_contact (group, priv->self_handle); -} - -gboolean -empathy_tp_group_is_member (EmpathyTpGroup *group, - EmpathyContact *contact) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), FALSE); - g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE); - - return g_list_find (priv->members, contact) != NULL; -} - -gboolean -empathy_tp_group_is_ready (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), FALSE); - - return priv->ready; -} - -EmpathyPendingInfo * -empathy_tp_group_get_invitation (EmpathyTpGroup *group, - EmpathyContact **remote_contact) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - EmpathyContact *contact = NULL; - EmpathyPendingInfo *invitation = NULL; - GList *l; - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), FALSE); - g_return_val_if_fail (priv->ready, NULL); - - for (l = priv->local_pendings; l; l = l->next) { - EmpathyPendingInfo *info = l->data; - - if (empathy_contact_is_user (info->member)) { - invitation = info; - break; - } - } - - if (invitation) { - contact = invitation->actor; - } - if (!invitation) { - if (priv->remote_pendings) { - contact = priv->remote_pendings->data; - } - else if (priv->members) { - contact = priv->members->data; - } - } - - if (remote_contact && contact) { - *remote_contact = g_object_ref (contact); - } - - return invitation; -} - -TpChannelGroupFlags -empathy_tp_group_get_flags (EmpathyTpGroup *self) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (self); - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (self), 0); - - if (priv->channel == NULL) - return 0; - - return tp_channel_group_get_flags (priv->channel); -} diff --git a/libempathy/empathy-tp-group.h b/libempathy/empathy-tp-group.h deleted file mode 100644 index 9e0dd53e..00000000 --- a/libempathy/empathy-tp-group.h +++ /dev/null @@ -1,93 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006 Xavier Claessens - * Copyright (C) 2007-2008 Collabora Ltd. - * - * This library 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.1 of the License, or (at your option) any later version. - * - * This library 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 library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Authors: Xavier Claessens - */ - -#ifndef __EMPATHY_TP_GROUP_H__ -#define __EMPATHY_TP_GROUP_H__ - -#include - -#include - -#include "empathy-contact.h" - -G_BEGIN_DECLS - -#define EMPATHY_TYPE_TP_GROUP (empathy_tp_group_get_type ()) -#define EMPATHY_TP_GROUP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_TP_GROUP, EmpathyTpGroup)) -#define EMPATHY_TP_GROUP_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_TP_GROUP, EmpathyTpGroupClass)) -#define EMPATHY_IS_TP_GROUP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_TP_GROUP)) -#define EMPATHY_IS_TP_GROUP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_TP_GROUP)) -#define EMPATHY_TP_GROUP_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_TP_GROUP, EmpathyTpGroupClass)) - -typedef struct _EmpathyTpGroup EmpathyTpGroup; -typedef struct _EmpathyTpGroupClass EmpathyTpGroupClass; - -struct _EmpathyTpGroup { - GObject parent; - gpointer priv; -}; - -struct _EmpathyTpGroupClass { - GObjectClass parent_class; -}; - -typedef struct { - EmpathyContact *member; - EmpathyContact *actor; - gchar *message; - guint reason; -} EmpathyPendingInfo; - -GType empathy_tp_group_get_type (void) G_GNUC_CONST; -EmpathyTpGroup * empathy_tp_group_new (TpChannel *channel); -void empathy_tp_group_close (EmpathyTpGroup *group); -void empathy_tp_group_add_members (EmpathyTpGroup *group, - GList *contacts, - const gchar *message); -void empathy_tp_group_add_member (EmpathyTpGroup *group, - EmpathyContact *contact, - const gchar *message); -void empathy_tp_group_remove_members (EmpathyTpGroup *group, - GList *contacts, - const gchar *message); -void empathy_tp_group_remove_member (EmpathyTpGroup *group, - EmpathyContact *contact, - const gchar *message); -GList * empathy_tp_group_get_members (EmpathyTpGroup *group); -GList * empathy_tp_group_get_local_pendings (EmpathyTpGroup *group); -GList * empathy_tp_group_get_remote_pendings (EmpathyTpGroup *group); -const gchar * empathy_tp_group_get_name (EmpathyTpGroup *group); -EmpathyContact * empathy_tp_group_get_self_contact (EmpathyTpGroup *group); -gboolean empathy_tp_group_is_member (EmpathyTpGroup *group, - EmpathyContact *contact); -gboolean empathy_tp_group_is_ready (EmpathyTpGroup *group); -EmpathyPendingInfo *empathy_tp_group_get_invitation (EmpathyTpGroup *group, - EmpathyContact **remote_contact); -EmpathyPendingInfo *empathy_pending_info_new (EmpathyContact *member, - EmpathyContact *actor, - const gchar *message); -void empathy_pending_info_free (EmpathyPendingInfo *info); -TpChannelGroupFlags empathy_tp_group_get_flags (EmpathyTpGroup *group); - -G_END_DECLS - -#endif /* __EMPATHY_TP_GROUP_H__ */ diff --git a/libempathy/empathy-tp-tube.c b/libempathy/empathy-tp-tube.c index 746708fc..7d22f6b7 100644 --- a/libempathy/empathy-tp-tube.c +++ b/libempathy/empathy-tp-tube.c @@ -390,8 +390,6 @@ empathy_tp_tube_new_stream_tube (EmpathyContact *contact, const gchar *service, GHashTable *parameters) { - MissionControl *mc; - McAccount *account; TpConnection *connection; TpChannel *channel; gchar *object_path; @@ -408,12 +406,7 @@ empathy_tp_tube_new_stream_tube (EmpathyContact *contact, g_return_val_if_fail (hostname != NULL, NULL); g_return_val_if_fail (service != NULL, NULL); - mc = empathy_mission_control_dup_singleton (); - account = empathy_contact_get_account (contact); - connection = mission_control_get_tpconnection (mc, account, NULL); - g_object_unref (mc); - - tp_connection_run_until_ready (connection, FALSE, NULL, NULL); + connection = empathy_contact_get_connection (contact); request = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) tp_g_value_slice_free); diff --git a/libempathy/empathy-utils.c b/libempathy/empathy-utils.c index a476d9e5..210c3504 100644 --- a/libempathy/empathy-utils.c +++ b/libempathy/empathy-utils.c @@ -37,7 +37,6 @@ #include #include "empathy-utils.h" -#include "empathy-contact-factory.h" #include "empathy-contact-manager.h" #include "empathy-dispatcher.h" #include "empathy-dispatch-operation.h" @@ -332,97 +331,6 @@ empathy_file_lookup (const gchar *filename, const gchar *subdir) return path; } -typedef struct { - EmpathyRunUntilReadyFunc func; - gpointer user_data; - GObject *object; - GMainLoop *loop; -} RunUntilReadyData; - -static void -run_until_ready_cb (RunUntilReadyData *data) -{ - if (!data->func || data->func (data->object, data->user_data)) { - DEBUG ("Object %p is ready", data->object); - g_main_loop_quit (data->loop); - } -} - -static gboolean -object_is_ready (GObject *object, - gpointer user_data) -{ - gboolean ready; - - g_object_get (object, "ready", &ready, NULL); - - return ready; -} - -void -empathy_run_until_ready_full (gpointer object, - const gchar *signal, - EmpathyRunUntilReadyFunc func, - gpointer user_data, - GMainLoop **loop) -{ - RunUntilReadyData data; - gulong signal_id; - - g_return_if_fail (G_IS_OBJECT (object)); - g_return_if_fail (signal != NULL); - - if (func && func (object, user_data)) { - return; - } - - DEBUG ("Starting run until ready for object %p", object); - - data.func = func; - data.user_data = user_data; - data.object = object; - data.loop = g_main_loop_new (NULL, FALSE); - - signal_id = g_signal_connect_swapped (object, signal, - G_CALLBACK (run_until_ready_cb), - &data); - if (loop != NULL) { - *loop = data.loop; - } - - g_main_loop_run (data.loop); - - if (loop != NULL) { - *loop = NULL; - } - - g_signal_handler_disconnect (object, signal_id); - g_main_loop_unref (data.loop); -} - -void -empathy_run_until_ready (gpointer object) -{ - empathy_run_until_ready_full (object, "notify::ready", object_is_ready, - NULL, NULL); -} - -McAccount * -empathy_channel_get_account (TpChannel *channel) -{ - TpConnection *connection; - McAccount *account; - MissionControl *mc; - - g_object_get (channel, "connection", &connection, NULL); - mc = empathy_mission_control_dup_singleton (); - account = mission_control_get_account_for_tpconnection (mc, connection, NULL); - g_object_unref (connection); - g_object_unref (mc); - - return account; -} - guint empathy_proxy_hash (gconstpointer key) { @@ -470,3 +378,4 @@ empathy_check_available_state (void) return TRUE; } + diff --git a/libempathy/empathy-utils.h b/libempathy/empathy-utils.h index 8684acc0..e6bcfebf 100644 --- a/libempathy/empathy-utils.h +++ b/libempathy/empathy-utils.h @@ -74,16 +74,6 @@ const gchar * empathy_presence_to_str (McPresence presence); McPresence empathy_presence_from_str (const gchar *str); gchar * empathy_file_lookup (const gchar *filename, const gchar *subdir); - -typedef gboolean (*EmpathyRunUntilReadyFunc) (GObject *object, - gpointer user_data); -void empathy_run_until_ready (gpointer object); -void empathy_run_until_ready_full (gpointer object, - const gchar *signal, - EmpathyRunUntilReadyFunc func, - gpointer user_data, - GMainLoop **loop); -McAccount * empathy_channel_get_account (TpChannel *channel); gboolean empathy_proxy_equal (gconstpointer a, gconstpointer b); guint empathy_proxy_hash (gconstpointer key); diff --git a/megaphone/src/megaphone-applet.c b/megaphone/src/megaphone-applet.c index 79eaac4d..0879e75a 100644 --- a/megaphone/src/megaphone-applet.c +++ b/megaphone/src/megaphone-applet.c @@ -1,7 +1,7 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2007 Raphaël Slinckx - * Copyright (C) 2007 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,7 +34,8 @@ #include #include -#include +#include +#include #include #include #include @@ -52,107 +53,19 @@ #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, MegaphoneApplet) typedef struct { - EmpathyContactFactory *factory; - GtkWidget *image; - gint image_size; - EmpathyContact *contact; - GConfClient *gconf; - guint gconf_cnxn; + EmpathyTpContactFactory *factory; + EmpathyAccountManager *account_manager; + McAccount *account; + gchar *id; + GtkWidget *image; + gint image_size; + EmpathyContact *contact; + GConfClient *gconf; + guint gconf_cnxn; } MegaphoneAppletPriv; -static void megaphone_applet_finalize (GObject *object); -static void megaphone_applet_size_allocate_cb (GtkWidget *widget, - GtkAllocation *allocation, - MegaphoneApplet *applet); -static gboolean megaphone_applet_button_press_event_cb (GtkWidget *widget, - GdkEventButton *event, - MegaphoneApplet *applet); -static void megaphone_applet_information_cb (BonoboUIComponent *uic, - MegaphoneApplet *applet, - const gchar *verb_name); -static void megaphone_applet_preferences_cb (BonoboUIComponent *uic, - MegaphoneApplet *applet, - const gchar *verb_name); -static void megaphone_applet_about_cb (BonoboUIComponent *uic, - MegaphoneApplet *applet, - const gchar *verb_name); - G_DEFINE_TYPE(MegaphoneApplet, megaphone_applet, PANEL_TYPE_APPLET) -static const BonoboUIVerb megaphone_applet_menu_verbs [] = { - BONOBO_UI_UNSAFE_VERB ("information", megaphone_applet_information_cb), - BONOBO_UI_UNSAFE_VERB ("preferences", megaphone_applet_preferences_cb), - BONOBO_UI_UNSAFE_VERB ("about", megaphone_applet_about_cb), - BONOBO_UI_VERB_END -}; - -static const char* authors[] = { - "Raphaël Slinckx ", - "Xavier Claessens ", - NULL -}; - -static void -megaphone_applet_class_init (MegaphoneAppletClass *class) -{ - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS (class); - - object_class->finalize = megaphone_applet_finalize; - - g_type_class_add_private (object_class, sizeof (MegaphoneAppletPriv)); - empathy_gtk_init (); -} - -static void -megaphone_applet_init (MegaphoneApplet *applet) -{ - MegaphoneAppletPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (applet, - MEGAPHONE_TYPE_APPLET, MegaphoneAppletPriv); - - applet->priv = priv; - priv->factory = empathy_contact_factory_dup_singleton (); - priv->gconf = gconf_client_get_default (); - - /* Image holds the contact avatar */ - priv->image = gtk_image_new (); - gtk_widget_show (priv->image); - gtk_container_add (GTK_CONTAINER (applet), priv->image); - - /* We want transparency */ - panel_applet_set_flags (PANEL_APPLET (applet), PANEL_APPLET_EXPAND_MINOR); - panel_applet_set_background_widget (PANEL_APPLET (applet), GTK_WIDGET (applet)); - - /* Listen for clicks on the applet to dispatch a channel */ - g_signal_connect (applet, "button-press-event", - G_CALLBACK (megaphone_applet_button_press_event_cb), - applet); - - /* Allow to resize our avatar when needed */ - g_signal_connect (applet, "size-allocate", - G_CALLBACK (megaphone_applet_size_allocate_cb), - applet); -} - -static void -megaphone_applet_finalize (GObject *object) -{ - MegaphoneAppletPriv *priv = GET_PRIV (object); - - if (priv->contact) { - g_object_unref (priv->contact); - } - g_object_unref (priv->factory); - - if (priv->gconf_cnxn != 0) { - gconf_client_notify_remove (priv->gconf, priv->gconf_cnxn); - } - g_object_unref (priv->gconf); - - G_OBJECT_CLASS (megaphone_applet_parent_class)->finalize (object); -} - static void megaphone_applet_update_icon (MegaphoneApplet *applet) { @@ -258,46 +171,42 @@ megaphone_applet_update_contact (MegaphoneApplet *applet) } static void -megaphone_applet_set_contact (MegaphoneApplet *applet, - const gchar *str) +megaphone_applet_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *applet) { MegaphoneAppletPriv *priv = GET_PRIV (applet); - McAccount *account = NULL; - gchar **strv = NULL; - - DEBUG ("Setting new contact %s", str); - /* Release old contact, if any */ - if (priv->contact) { - g_signal_handlers_disconnect_by_func (priv->contact, - megaphone_applet_update_contact, - applet); - g_object_unref (priv->contact), - priv->contact = NULL; + if (error != NULL) { + DEBUG ("Error: %s", error->message); + return; } - /* Lookup the new contact */ - if (str) { - strv = g_strsplit (str, "/", 2); - account = mc_account_lookup (strv[0]); - } - if (account) { - priv->contact = empathy_contact_factory_get_from_id (priv->factory, - account, - strv[1]); - g_object_unref (account); - } - g_strfreev (strv); + priv->contact = g_object_ref (contact); + g_signal_connect_swapped (priv->contact, "notify", + G_CALLBACK (megaphone_applet_update_contact), + applet); + megaphone_applet_update_contact (MEGAPHONE_APPLET (applet)); +} - /* Take hold of the new contact if any */ - if (priv->contact) { - /* Listen for updates on the contact, and force a first update */ - g_signal_connect_swapped (priv->contact, "notify", - G_CALLBACK (megaphone_applet_update_contact), - applet); +static void +megaphone_applet_new_connection_cb (EmpathyAccountManager *manager, + TpConnection *connection, + McAccount *account, + MegaphoneApplet *applet) +{ + MegaphoneAppletPriv *priv = GET_PRIV (applet); + + if (priv->contact || !empathy_account_equal (account, priv->account)) { + return; } - megaphone_applet_update_contact (applet); + priv->factory = empathy_tp_contact_factory_dup_singleton (connection); + empathy_tp_contact_factory_get_from_id (priv->factory, priv->id, + megaphone_applet_got_contact_cb, + NULL, NULL, G_OBJECT (applet)); } static void @@ -312,7 +221,7 @@ megaphone_applet_preferences_response_cb (GtkWidget *dialog, /* Retrieve the selected contact, if any and set it up in gconf. * GConf will notify us from the change and we will adjust ourselves */ contact_list = g_object_get_data (G_OBJECT (dialog), "contact-list"); - contact = empathy_contact_list_view_get_selected (contact_list); + contact = empathy_contact_list_view_dup_selected (contact_list); if (contact) { McAccount *account; const gchar *account_id; @@ -331,6 +240,7 @@ megaphone_applet_preferences_response_cb (GtkWidget *dialog, "contact_id", str, NULL); g_free (str); + g_object_unref (contact); } } gtk_widget_destroy (dialog); @@ -384,42 +294,6 @@ megaphone_applet_show_preferences (MegaphoneApplet *applet) gtk_widget_show (dialog); } -static void -megaphone_applet_information_cb (BonoboUIComponent *uic, - MegaphoneApplet *applet, - const gchar *verb_name) -{ - MegaphoneAppletPriv *priv = GET_PRIV (applet); - - /* FIXME: We should grey out the menu item if there are no available contact */ - if (priv->contact) { - empathy_contact_information_dialog_show (priv->contact, NULL, FALSE, FALSE); - } -} - -static void -megaphone_applet_preferences_cb (BonoboUIComponent *uic, - MegaphoneApplet *applet, - const gchar *verb_name) -{ - megaphone_applet_show_preferences (applet); -} - -static void -megaphone_applet_about_cb (BonoboUIComponent *uic, - MegaphoneApplet *applet, - const gchar *verb_name) -{ - gtk_show_about_dialog (NULL, - "name", "Megaphone", - "version", PACKAGE_VERSION, - "copyright", "Raphaël Slinckx 2007\nCollabora Ltd 2007", - "comments", _("Talk!"), - "authors", authors, - "logo-icon-name", "stock_people", - NULL); -} - static gboolean megaphone_applet_button_press_event_cb (GtkWidget *widget, GdkEventButton *event, @@ -478,6 +352,144 @@ megaphone_applet_size_allocate_cb (GtkWidget *widget, } } +static void +megaphone_applet_finalize (GObject *object) +{ + MegaphoneAppletPriv *priv = GET_PRIV (object); + + if (priv->contact) { + g_object_unref (priv->contact); + } + if (priv->factory) { + g_object_unref (priv->factory); + } + if (priv->account_manager) { + g_signal_handlers_disconnect_by_func (priv->account_manager, + megaphone_applet_new_connection_cb, object); + g_object_unref (priv->account_manager); + } + + if (priv->gconf_cnxn != 0) { + gconf_client_notify_remove (priv->gconf, priv->gconf_cnxn); + } + g_object_unref (priv->gconf); + g_free (priv->id); + + G_OBJECT_CLASS (megaphone_applet_parent_class)->finalize (object); +} + +static void +megaphone_applet_class_init (MegaphoneAppletClass *class) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (class); + + object_class->finalize = megaphone_applet_finalize; + + g_type_class_add_private (object_class, sizeof (MegaphoneAppletPriv)); + empathy_gtk_init (); +} + +static void +megaphone_applet_init (MegaphoneApplet *applet) +{ + MegaphoneAppletPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (applet, + MEGAPHONE_TYPE_APPLET, MegaphoneAppletPriv); + + applet->priv = priv; + priv->gconf = gconf_client_get_default (); + priv->account_manager = empathy_account_manager_dup_singleton (); + g_signal_connect (priv->account_manager, "new-connection", + G_CALLBACK (megaphone_applet_new_connection_cb), applet); + + /* Image holds the contact avatar */ + priv->image = gtk_image_new (); + gtk_widget_show (priv->image); + gtk_container_add (GTK_CONTAINER (applet), priv->image); + + /* We want transparency */ + panel_applet_set_flags (PANEL_APPLET (applet), PANEL_APPLET_EXPAND_MINOR); + panel_applet_set_background_widget (PANEL_APPLET (applet), GTK_WIDGET (applet)); + + /* Listen for clicks on the applet to dispatch a channel */ + g_signal_connect (applet, "button-press-event", + G_CALLBACK (megaphone_applet_button_press_event_cb), + applet); + + /* Allow to resize our avatar when needed */ + g_signal_connect (applet, "size-allocate", + G_CALLBACK (megaphone_applet_size_allocate_cb), + applet); +} + +static void +megaphone_applet_set_contact (MegaphoneApplet *applet, + const gchar *str) +{ + MegaphoneAppletPriv *priv = GET_PRIV (applet); + TpConnection *connection; + gchar **strv = NULL; + + DEBUG ("Setting new contact %s", str); + + /* Release old contact, if any */ + if (priv->contact) { + g_signal_handlers_disconnect_by_func (priv->contact, + megaphone_applet_update_contact, + applet); + g_object_unref (priv->contact), + priv->contact = NULL; + } + if (priv->account) { + g_object_unref (priv->account), + priv->account = NULL; + } + if (priv->factory) { + g_object_unref (priv->factory), + priv->factory = NULL; + } + + /* Lookup the new contact */ + if (str) { + strv = g_strsplit (str, "/", 2); + priv->account = mc_account_lookup (strv[0]); + priv->id = strv[1]; + g_free (strv[0]); + g_free (strv); + } + + if (priv->account) { + connection = empathy_account_manager_get_connection ( + priv->account_manager, priv->account); + if (connection) { + megaphone_applet_new_connection_cb (priv->account_manager, + connection, priv->account, applet); + } + } +} + +static void +megaphone_applet_information_cb (BonoboUIComponent *uic, + MegaphoneApplet *applet, + const gchar *verb_name) +{ + MegaphoneAppletPriv *priv = GET_PRIV (applet); + + /* FIXME: We should grey out the menu item if there are no available contact */ + if (priv->contact) { + empathy_contact_information_dialog_show (priv->contact, NULL); + } +} + +static void +megaphone_applet_preferences_cb (BonoboUIComponent *uic, + MegaphoneApplet *applet, + const gchar *verb_name) +{ + megaphone_applet_show_preferences (applet); +} + static void megaphone_applet_gconf_notify_cb (GConfClient *client, guint cnxn_id, @@ -497,6 +509,34 @@ megaphone_applet_gconf_notify_cb (GConfClient *client, } } +static void +megaphone_applet_about_cb (BonoboUIComponent *uic, + MegaphoneApplet *applet, + const gchar *verb_name) +{ + const char* authors[] = { + "Raphaël Slinckx ", + "Xavier Claessens ", + NULL + }; + + gtk_show_about_dialog (NULL, + "name", "Megaphone", + "version", PACKAGE_VERSION, + "copyright", "Raphaël Slinckx 2007\nCollabora Ltd 2007", + "comments", _("Talk!"), + "authors", authors, + "logo-icon-name", "stock_people", + NULL); +} + +static const BonoboUIVerb megaphone_applet_menu_verbs [] = { + BONOBO_UI_UNSAFE_VERB ("information", megaphone_applet_information_cb), + BONOBO_UI_UNSAFE_VERB ("preferences", megaphone_applet_preferences_cb), + BONOBO_UI_UNSAFE_VERB ("about", megaphone_applet_about_cb), + BONOBO_UI_VERB_END +}; + static gboolean megaphone_applet_factory (PanelApplet *applet, const gchar *iid, diff --git a/po/POTFILES.in b/po/POTFILES.in index 32c38153..c29bb60c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -37,9 +37,8 @@ libempathy-gtk/empathy-log-window.c [type: gettext/glade]libempathy-gtk/empathy-log-window.ui [type: gettext/glade]libempathy-gtk/empathy-new-message-dialog.ui libempathy-gtk/empathy-presence-chooser.c -[type: gettext/glade]libempathy-gtk/empathy-presence-chooser.ui -libempathy-gtk/empathy-spell-dialog.c -[type: gettext/glade]libempathy-gtk/empathy-spell-dialog.ui +libempathy-gtk/empathy-status-preset-dialog.c +[type: gettext/glade]libempathy-gtk/empathy-status-preset-dialog.ui libempathy-gtk/empathy-theme-boxes.c libempathy-gtk/empathy-theme-irc.c libempathy-gtk/empathy-theme-manager.c diff --git a/po/es.po b/po/es.po index 15eb63c3..7e5b0c26 100644 --- a/po/es.po +++ b/po/es.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: empathy.HEAD\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" "product=empathy&component=general\n" -"POT-Creation-Date: 2009-04-17 20:26+0000\n" -"PO-Revision-Date: 2009-04-18 20:33+0200\n" +"POT-Creation-Date: 2009-04-21 15:44+0000\n" +"PO-Revision-Date: 2009-04-21 21:02+0200\n" "Last-Translator: Jorge González \n" "Language-Team: Español \n" "MIME-Version: 1.0\n" @@ -355,7 +355,7 @@ msgstr "" "predeterminado es ordenar por el nombre del contacto con el valor \"name" "\" (nombre). Un valor \"state\" (estado) ordenará la lista por el estado." -#: ../libempathy/empathy-tp-contact-list.c:731 ../src/empathy.c:271 +#: ../libempathy/empathy-tp-contact-list.c:732 ../src/empathy.c:271 msgid "People nearby" msgstr "Gente cerca" @@ -571,7 +571,7 @@ msgid "_Room List locale:" msgstr "Configuración de la lista de _salas:" #: ../libempathy-gtk/empathy-avatar-chooser.c:462 -#: ../libempathy-gtk/empathy-avatar-chooser.c:537 +#: ../libempathy-gtk/empathy-avatar-chooser.c:538 msgid "Couldn't convert image" msgstr "No se pudo convertir la imagen" @@ -579,19 +579,19 @@ msgstr "No se pudo convertir la imagen" msgid "None of the accepted image formats is supported on your system" msgstr "Su sistema no soporta ninguno de los formatos de imagen aceptados" -#: ../libempathy-gtk/empathy-avatar-chooser.c:954 +#: ../libempathy-gtk/empathy-avatar-chooser.c:957 msgid "Select Your Avatar Image" msgstr "Seleccione su imagen de avatar" -#: ../libempathy-gtk/empathy-avatar-chooser.c:957 +#: ../libempathy-gtk/empathy-avatar-chooser.c:960 msgid "No Image" msgstr "Sin imagen" -#: ../libempathy-gtk/empathy-avatar-chooser.c:1019 +#: ../libempathy-gtk/empathy-avatar-chooser.c:1022 msgid "Images" msgstr "Imágenes" -#: ../libempathy-gtk/empathy-avatar-chooser.c:1023 +#: ../libempathy-gtk/empathy-avatar-chooser.c:1026 msgid "All Files" msgstr "Todos los archivos" @@ -761,7 +761,8 @@ msgid "_Chat" msgstr "_Chat" #: ../libempathy-gtk/empathy-contact-menu.c:161 -#: ../src/empathy-call-window.ui.h:5 +#| msgid "_Call" +msgctxt "menu item" msgid "_Call" msgstr "_Llamar" @@ -787,7 +788,7 @@ msgstr "_Editar" msgid "Inviting to this room" msgstr "Invitando a esta sala" -#: ../libempathy-gtk/empathy-contact-menu.c:369 +#: ../libempathy-gtk/empathy-contact-menu.c:367 msgid "_Invite to chatroom" msgstr "_Invitar a la sala" @@ -795,19 +796,19 @@ msgstr "_Invitar a la sala" msgid "Select a contact" msgstr "Seleccionar un contacto" -#: ../libempathy-gtk/empathy-contact-widget.c:354 +#: ../libempathy-gtk/empathy-contact-widget.c:353 msgid "Save Avatar" msgstr "Guardar avatar" -#: ../libempathy-gtk/empathy-contact-widget.c:410 +#: ../libempathy-gtk/empathy-contact-widget.c:409 msgid "Unable to save avatar" msgstr "No se pudo guardar el avatar" -#: ../libempathy-gtk/empathy-contact-widget.c:905 +#: ../libempathy-gtk/empathy-contact-widget.c:904 msgid "Select" msgstr "Seleccionar" -#: ../libempathy-gtk/empathy-contact-widget.c:914 +#: ../libempathy-gtk/empathy-contact-widget.c:913 #: ../src/empathy-main-window.c:882 msgid "Group" msgstr "Grupo" @@ -959,16 +960,24 @@ msgstr "Mensaje personalizado…" msgid "Edit Custom Messages..." msgstr "Editar mensajes personalizados…" -#: ../libempathy-gtk/empathy-presence-chooser.c:269 +#: ../libempathy-gtk/empathy-presence-chooser.c:316 +msgid "Click to remove this status as a favorite" +msgstr "Pulse pare eliminar este estado de los favoritos" + +#: ../libempathy-gtk/empathy-presence-chooser.c:325 +msgid "Click to make this status a favorite" +msgstr "Pulse para hacer este estado uno favorito" + +#: ../libempathy-gtk/empathy-presence-chooser.c:359 msgid "Set status" msgstr "Establecer estado" -#: ../libempathy-gtk/empathy-presence-chooser.c:653 +#: ../libempathy-gtk/empathy-presence-chooser.c:766 msgid "Set your presence and current status" msgstr "Establecer su presencia y estado actual" #. Custom messages -#: ../libempathy-gtk/empathy-presence-chooser.c:873 +#: ../libempathy-gtk/empathy-presence-chooser.c:987 msgid "Custom messages..." msgstr "Mensajes personalizados…" @@ -1419,6 +1428,11 @@ msgstr "" msgid "Type:" msgstr "Tipo:" +#: ../src/empathy-accounts-dialog.ui.h:10 +#| msgid "_Add Contact..." +msgid "_Add..." +msgstr "_Añadir…" + #: ../src/empathy-call-window.c:319 msgid "Contrast" msgstr "Contraste" @@ -1477,6 +1491,10 @@ msgstr "Enviar vídeo" msgid "Video preview" msgstr "Vista preliminar de vídeo" +#: ../src/empathy-call-window.ui.h:5 +msgid "_Call" +msgstr "_Llamar" + #: ../src/empathy-call-window.ui.h:6 msgid "_View" msgstr "_Ver" @@ -1658,7 +1676,6 @@ msgid "%s of %s" msgstr "%s de %s" #: ../src/empathy-ft-manager.c:254 -#| msgid "Waiting the other participant's response" msgid "Waiting for the other participant's response" msgstr "Esperando la respuesta del otro participante" @@ -1840,7 +1857,7 @@ msgstr "Error desconocido" msgid "Contact" msgstr "Contacto" -#: ../src/empathy-main-window.c:1202 +#: ../src/empathy-main-window.c:1205 msgid "Show and edit accounts" msgstr "Mostrar y editar cuentas" @@ -1881,7 +1898,6 @@ msgid "_Help" msgstr "Ay_uda" #: ../src/empathy-main-window.ui.h:12 -#| msgid "_Join" msgid "_Join..." msgstr "_Unirse…" @@ -1898,12 +1914,10 @@ msgid "_Room" msgstr "_Sala" #: ../src/empathy-new-chatroom-dialog.c:313 -#| msgid "Chat Rooms" msgid "Chat Room" msgstr "Sala de chat" #: ../src/empathy-new-chatroom-dialog.c:328 -#| msgid "Themes" msgid "Members" msgstr "Miembros" @@ -1949,12 +1963,10 @@ msgstr "" "la cuenta del servidor actual" #: ../src/empathy-new-chatroom-dialog.ui.h:4 -#| msgid "Room" msgid "Join Room" msgstr "Unirse a sala" #: ../src/empathy-new-chatroom-dialog.ui.h:5 -#| msgid "_Room List locale:" msgid "Room List" msgstr "Lista de salas" @@ -1990,7 +2002,7 @@ msgstr "Cuenta conectada" msgid "Account disconnected" msgstr "Cuenta desconectada" -#: ../src/empathy-preferences.c:396 +#: ../src/empathy-preferences.c:397 msgid "Language" msgstr "Idioma" @@ -2116,12 +2128,12 @@ msgstr "_Salir" msgid "_Show Contact List" msgstr "_Mostrar lista de contactos" -#: ../src/empathy-tube-dispatch.c:364 +#: ../src/empathy-tube-dispatch.c:375 #, c-format msgid "Unable to start application for service %s: %s" msgstr "No se pudo iniciar la aplicación para el servicio %s: %s" -#: ../src/empathy-tube-dispatch.c:435 +#: ../src/empathy-tube-dispatch.c:446 #, c-format msgid "" "An invitation was offered for service %s, but you don't have the needed " diff --git a/python/pyempathy/pyempathy.defs b/python/pyempathy/pyempathy.defs index 66a26978..3e9fd624 100644 --- a/python/pyempathy/pyempathy.defs +++ b/python/pyempathy/pyempathy.defs @@ -42,13 +42,6 @@ (gtype-id "EMPATHY_TYPE_CONTACT") ) -(define-object ContactFactory - (in-module "Empathy") - (parent "GObject") - (c-name "EmpathyContactFactory") - (gtype-id "EMPATHY_TYPE_CONTACT_FACTORY") -) - (define-interface ContactList (in-module "Empathy") (c-name "EmpathyContactList") @@ -169,13 +162,6 @@ (gtype-id "EMPATHY_TYPE_TP_FILE") ) -(define-object TpGroup - (in-module "Empathy") - (parent "GObject") - (c-name "EmpathyTpGroup") - (gtype-id "EMPATHY_TYPE_TP_GROUP") -) - (define-object TpRoomlist (in-module "Empathy") (parent "GObject") @@ -212,19 +198,6 @@ ) ) -(define-flags ContactReady - (in-module "Empathy") - (c-name "EmpathyContactReady") - (gtype-id "EMPATHY_TYPE_CONTACT_READY") - (values - '("none" "EMPATHY_CONTACT_READY_NONE") - '("id" "EMPATHY_CONTACT_READY_ID") - '("handle" "EMPATHY_CONTACT_READY_HANDLE") - '("name" "EMPATHY_CONTACT_READY_NAME") - '("all" "EMPATHY_CONTACT_READY_ALL") - ) -) - (define-flags DebugFlags (in-module "Empathy") (c-name "EmpathyDebugFlags") @@ -307,6 +280,36 @@ (return-type "int") ) +(define-method get_account + (of-object "EmpathyAccountManager") + (c-name "empathy_account_manager_get_account") + (return-type "McAccount*") + (parameters + '("TpConnection*" "connection") + ) +) + +(define-method dup_accounts + (of-object "EmpathyAccountManager") + (c-name "empathy_account_manager_dup_accounts") + (return-type "GList*") +) + +(define-method get_connection + (of-object "EmpathyAccountManager") + (c-name "empathy_account_manager_get_connection") + (return-type "TpConnection*") + (parameters + '("McAccount*" "account") + ) +) + +(define-method dup_connections + (of-object "EmpathyAccountManager") + (c-name "empathy_account_manager_dup_connections") + (return-type "GList*") +) + ;; From empathy-chatroom.h @@ -396,6 +399,66 @@ ) ) +(define-method get_subject + (of-object "EmpathyChatroom") + (c-name "empathy_chatroom_get_subject") + (return-type "const-gchar*") +) + +(define-method set_subject + (of-object "EmpathyChatroom") + (c-name "empathy_chatroom_set_subject") + (return-type "none") + (parameters + '("const-gchar*" "subject") + ) +) + +(define-method get_members_count + (of-object "EmpathyChatroom") + (c-name "empathy_chatroom_get_members_count") + (return-type "guint") +) + +(define-method set_members_count + (of-object "EmpathyChatroom") + (c-name "empathy_chatroom_set_members_count") + (return-type "none") + (parameters + '("guint" "count") + ) +) + +(define-method get_need_password + (of-object "EmpathyChatroom") + (c-name "empathy_chatroom_get_need_password") + (return-type "gboolean") +) + +(define-method set_need_password + (of-object "EmpathyChatroom") + (c-name "empathy_chatroom_set_need_password") + (return-type "none") + (parameters + '("gboolean" "need_password") + ) +) + +(define-method get_invite_only + (of-object "EmpathyChatroom") + (c-name "empathy_chatroom_get_invite_only") + (return-type "gboolean") +) + +(define-method set_invite_only + (of-object "EmpathyChatroom") + (c-name "empathy_chatroom_set_invite_only") + (return-type "none") + (parameters + '("gboolean" "invite_only") + ) +) + (define-function chatroom_equal (c-name "empathy_chatroom_equal") (return-type "gboolean") @@ -575,18 +638,14 @@ (is-constructor-of "EmpathyContact") (return-type "EmpathyContact*") (parameters - '("McAccount*" "account") + '("TpContact*" "tp_contact") ) ) -(define-function contact_new_full - (c-name "empathy_contact_new_full") - (return-type "EmpathyContact*") - (parameters - '("McAccount*" "account") - '("const-gchar*" "id") - '("const-gchar*" "name") - ) +(define-method get_tp_contact + (of-object "EmpathyContact") + (c-name "empathy_contact_get_tp_contact") + (return-type "TpContact*") ) (define-method get_id @@ -640,13 +699,10 @@ (return-type "McAccount*") ) -(define-method set_account +(define-method get_connection (of-object "EmpathyContact") - (c-name "empathy_contact_set_account") - (return-type "none") - (parameters - '("McAccount*" "account") - ) + (c-name "empathy_contact_get_connection") + (return-type "TpConnection*") ) (define-method get_presence @@ -709,12 +765,6 @@ ) ) -(define-method get_ready - (of-object "EmpathyContact") - (c-name "empathy_contact_get_ready") - (return-type "EmpathyContactReady") -) - (define-method is_user (of-object "EmpathyContact") (c-name "empathy_contact_is_user") @@ -754,15 +804,6 @@ (return-type "gboolean") ) -(define-function contact_equal - (c-name "empathy_contact_equal") - (return-type "gboolean") - (parameters - '("gconstpointer" "v1") - '("gconstpointer" "v2") - ) -) - (define-function contact_hash (c-name "empathy_contact_hash") (return-type "guint") @@ -771,29 +812,6 @@ ) ) -(define-method call_when_ready - (of-object "EmpathyContact") - (c-name "empathy_contact_call_when_ready") - (return-type "none") - (parameters - '("EmpathyContactReady" "ready") - '("EmpathyContactReadyCb*" "callback") - '("gpointer" "user_data") - '("GDestroyNotify" "destroy") - '("GObject*" "weak_object") - ) -) - -(define-method run_until_ready - (of-object "EmpathyContact") - (c-name "empathy_contact_run_until_ready") - (return-type "none") - (parameters - '("EmpathyContactReady" "ready") - '("GMainLoop**" "loop") - ) -) - (define-method load_avatar_data (of-object "EmpathyContact") (c-name "empathy_contact_load_avatar_data") @@ -856,90 +874,6 @@ -;; From empathy-contact-factory.h - -(define-function contact_factory_get_type - (c-name "empathy_contact_factory_get_type") - (return-type "GType") -) - -(define-function contact_factory_dup_singleton - (c-name "empathy_contact_factory_dup_singleton") - (return-type "EmpathyContactFactory*") -) - -(define-method get_tp_factory - (of-object "EmpathyContactFactory") - (c-name "empathy_contact_factory_get_tp_factory") - (return-type "EmpathyTpContactFactory*") - (parameters - '("McAccount*" "account") - ) -) - -(define-method get_user - (of-object "EmpathyContactFactory") - (c-name "empathy_contact_factory_get_user") - (return-type "EmpathyContact*") - (parameters - '("McAccount*" "account") - ) -) - -(define-method get_from_id - (of-object "EmpathyContactFactory") - (c-name "empathy_contact_factory_get_from_id") - (return-type "EmpathyContact*") - (parameters - '("McAccount*" "account") - '("const-gchar*" "id") - ) -) - -(define-method get_from_handle - (of-object "EmpathyContactFactory") - (c-name "empathy_contact_factory_get_from_handle") - (return-type "EmpathyContact*") - (parameters - '("McAccount*" "account") - '("guint" "handle") - ) -) - -(define-method get_from_handles - (of-object "EmpathyContactFactory") - (c-name "empathy_contact_factory_get_from_handles") - (return-type "GList*") - (parameters - '("McAccount*" "account") - '("const-GArray*" "handles") - ) -) - -(define-method set_alias - (of-object "EmpathyContactFactory") - (c-name "empathy_contact_factory_set_alias") - (return-type "none") - (parameters - '("EmpathyContact*" "contact") - '("const-gchar*" "alias") - ) -) - -(define-method set_avatar - (of-object "EmpathyContactFactory") - (c-name "empathy_contact_factory_set_avatar") - (return-type "none") - (parameters - '("McAccount*" "account") - '("const-gchar*" "data") - '("gsize" "size") - '("const-gchar*" "mime_type") - ) -) - - - ;; From empathy-contact-groups.h (define-function contact_groups_get_all @@ -1084,7 +1018,7 @@ (c-name "empathy_contact_manager_get_list") (return-type "EmpathyTpContactList*") (parameters - '("McAccount*" "account") + '("TpConnection*" "connection") ) ) @@ -1093,7 +1027,7 @@ (c-name "empathy_contact_manager_can_add") (return-type "gboolean") (parameters - '("McAccount*" "account") + '("TpConnection*" "connection") ) ) @@ -1167,28 +1101,18 @@ (c-name "empathy_dispatcher_create_channel") (return-type "none") (parameters - '("McAccount*" "account") + '("TpConnection*" "connection") '("GHashTable*" "request") '("EmpathyDispatcherRequestCb*" "callback") '("gpointer" "user_data") ) ) -(define-function dispatcher_call_with_contact - (c-name "empathy_dispatcher_call_with_contact") - (return-type "none") - (parameters - '("EmpathyContact*" "contact") - '("EmpathyDispatcherRequestCb*" "callback") - '("gpointer" "user_data") - ) -) - (define-function dispatcher_chat_with_contact_id (c-name "empathy_dispatcher_chat_with_contact_id") (return-type "none") (parameters - '("McAccount*" "account") + '("TpConnection*" "connection") '("const-gchar*" "contact_id") '("EmpathyDispatcherRequestCb*" "callback") '("gpointer" "user_data") @@ -1223,7 +1147,7 @@ (c-name "empathy_dispatcher_join_muc") (return-type "none") (parameters - '("McAccount*" "account") + '("TpConnection*" "connection") '("const-gchar*" "roomname") '("EmpathyDispatcherRequestCb*" "callback") '("gpointer" "user_data") @@ -1235,7 +1159,7 @@ (c-name "empathy_dispatcher_find_channel_class") (return-type "GStrv") (parameters - '("McAccount*" "account") + '("TpConnection*" "connection") '("const-gchar*" "channel_type") '("guint" "handle_type") ) @@ -2169,28 +2093,22 @@ (return-type "EmpathyContact*") ) -(define-method get_account - (of-object "EmpathyTpChat") - (c-name "empathy_tp_chat_get_account") - (return-type "McAccount*") -) - (define-method get_channel (of-object "EmpathyTpChat") (c-name "empathy_tp_chat_get_channel") (return-type "TpChannel*") ) -(define-method is_ready +(define-method get_connection (of-object "EmpathyTpChat") - (c-name "empathy_tp_chat_is_ready") - (return-type "gboolean") + (c-name "empathy_tp_chat_get_connection") + (return-type "TpConnection*") ) -(define-method get_members_count +(define-method is_ready (of-object "EmpathyTpChat") - (c-name "empathy_tp_chat_get_members_count") - (return-type "guint") + (c-name "empathy_tp_chat_is_ready") + (return-type "gboolean") ) (define-method send @@ -2254,45 +2172,39 @@ (return-type "GType") ) -(define-function tp_contact_factory_new - (c-name "empathy_tp_contact_factory_new") - (is-constructor-of "EmpathyTpContactFactory") +(define-function tp_contact_factory_dup_singleton + (c-name "empathy_tp_contact_factory_dup_singleton") (return-type "EmpathyTpContactFactory*") (parameters - '("McAccount*" "account") - ) -) - -(define-method get_user - (of-object "EmpathyTpContactFactory") - (c-name "empathy_tp_contact_factory_get_user") - (return-type "EmpathyContact*") -) - -(define-method get_from_id - (of-object "EmpathyTpContactFactory") - (c-name "empathy_tp_contact_factory_get_from_id") - (return-type "EmpathyContact*") - (parameters - '("const-gchar*" "id") + '("TpConnection*" "connection") ) ) -(define-method get_from_handle +(define-method get_from_ids (of-object "EmpathyTpContactFactory") - (c-name "empathy_tp_contact_factory_get_from_handle") - (return-type "EmpathyContact*") + (c-name "empathy_tp_contact_factory_get_from_ids") + (return-type "none") (parameters - '("guint" "handle") + '("guint" "n_ids") + '("const-gchar*-const*" "ids") + '("EmpathyTpContactFactoryGotContactsCb" "callback") + '("gpointer" "user_data") + '("GDestroyNotify" "destroy") + '("GObject*" "weak_object") ) ) (define-method get_from_handles (of-object "EmpathyTpContactFactory") (c-name "empathy_tp_contact_factory_get_from_handles") - (return-type "GList*") + (return-type "none") (parameters - '("const-GArray*" "handles") + '("guint" "n_handles") + '("const-TpHandle*" "handles") + '("EmpathyTpContactFactoryGotContactsCb" "callback") + '("gpointer" "user_data") + '("GDestroyNotify" "destroy") + '("GObject*" "weak_object") ) ) @@ -2317,12 +2229,6 @@ ) ) -(define-method is_ready - (of-object "EmpathyTpContactFactory") - (c-name "empathy_tp_contact_factory_is_ready") - (return-type "gboolean") -) - ;; From empathy-tp-contact-list.h @@ -2337,14 +2243,14 @@ (is-constructor-of "EmpathyTpContactList") (return-type "EmpathyTpContactList*") (parameters - '("McAccount*" "account") + '("TpConnection*" "connection") ) ) -(define-method get_account +(define-method get_connection (of-object "EmpathyTpContactList") - (c-name "empathy_tp_contact_list_get_account") - (return-type "McAccount*") + (c-name "empathy_tp_contact_list_get_connection") + (return-type "TpConnection*") ) (define-method can_add @@ -2353,6 +2259,12 @@ (return-type "gboolean") ) +(define-method remove_all + (of-object "EmpathyTpContactList") + (c-name "empathy_tp_contact_list_remove_all") + (return-type "none") +) + ;; From empathy-tp-file.h @@ -2461,147 +2373,12 @@ (return-type "const-gchar*") ) - - -;; From empathy-tp-group.h - -(define-function tp_group_get_type - (c-name "empathy_tp_group_get_type") - (return-type "GType") -) - -(define-function tp_group_new - (c-name "empathy_tp_group_new") - (is-constructor-of "EmpathyTpGroup") - (return-type "EmpathyTpGroup*") - (parameters - '("TpChannel*" "channel") - ) -) - -(define-method close - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_close") - (return-type "none") -) - -(define-method add_members - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_add_members") - (return-type "none") - (parameters - '("GList*" "contacts") - '("const-gchar*" "message") - ) -) - -(define-method add_member - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_add_member") - (return-type "none") - (parameters - '("EmpathyContact*" "contact") - '("const-gchar*" "message") - ) -) - -(define-method remove_members - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_remove_members") - (return-type "none") - (parameters - '("GList*" "contacts") - '("const-gchar*" "message") - ) -) - -(define-method remove_member - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_remove_member") - (return-type "none") - (parameters - '("EmpathyContact*" "contact") - '("const-gchar*" "message") - ) -) - -(define-method get_members - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_get_members") - (return-type "GList*") -) - -(define-method get_local_pendings - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_get_local_pendings") - (return-type "GList*") -) - -(define-method get_remote_pendings - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_get_remote_pendings") - (return-type "GList*") -) - -(define-method get_name - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_get_name") - (return-type "const-gchar*") -) - -(define-method get_self_contact - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_get_self_contact") - (return-type "EmpathyContact*") -) - -(define-method is_member - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_is_member") - (return-type "gboolean") - (parameters - '("EmpathyContact*" "contact") - ) -) - (define-method is_ready - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_is_ready") + (of-object "EmpathyTpFile") + (c-name "empathy_tp_file_is_ready") (return-type "gboolean") ) -(define-method get_invitation - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_get_invitation") - (return-type "EmpathyPendingInfo*") - (parameters - '("EmpathyContact**" "remote_contact") - ) -) - -(define-function pending_info_new - (c-name "empathy_pending_info_new") - (is-constructor-of "EmpathyPendingInfo") - (return-type "EmpathyPendingInfo*") - (parameters - '("EmpathyContact*" "member") - '("EmpathyContact*" "actor") - '("const-gchar*" "message") - ) -) - -(define-method free - (of-object "EmpathyPendingInfo") - (c-name "empathy_pending_info_free") - (return-type "none") -) - -(define-method get_flags - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_get_flags") - (return-type "TpChannelGroupFlags") -) - ;; From empathy-tp-roomlist.h @@ -2851,34 +2628,6 @@ ) ) -(define-function run_until_ready - (c-name "empathy_run_until_ready") - (return-type "none") - (parameters - '("gpointer" "object") - ) -) - -(define-function run_until_ready_full - (c-name "empathy_run_until_ready_full") - (return-type "none") - (parameters - '("gpointer" "object") - '("const-gchar*" "signal") - '("EmpathyRunUntilReadyFunc" "func") - '("gpointer" "user_data") - '("GMainLoop**" "loop") - ) -) - -(define-function channel_get_account - (c-name "empathy_channel_get_account") - (return-type "McAccount*") - (parameters - '("TpChannel*" "channel") - ) -) - (define-function proxy_equal (c-name "empathy_proxy_equal") (return-type "gboolean") diff --git a/python/pyempathy/pyempathy.override b/python/pyempathy/pyempathy.override index 72d7ccb0..e4c99086 100644 --- a/python/pyempathy/pyempathy.override +++ b/python/pyempathy/pyempathy.override @@ -7,7 +7,6 @@ headers #include "empathy-chatroom.h" #include "empathy-chatroom-manager.h" #include "empathy-contact.h" -#include "empathy-contact-factory.h" #include "empathy-contact-groups.h" #include "empathy-contact-list.h" #include "empathy-contact-manager.h" @@ -29,7 +28,6 @@ headers #include "empathy-tp-contact-factory.h" #include "empathy-tp-contact-list.h" #include "empathy-tp-file.h" -#include "empathy-tp-group.h" #include "empathy-tp-roomlist.h" #include "empathy-tp-tube.h" #include "empathy-tube-handler.h" @@ -66,25 +64,3 @@ _wrap_empathy_contact_list_get_members(PyGObject *self, PyObject *args, PyObject } %% -override empathy_dispatcher_chat_with_contact_id kwargs -static PyObject * -_wrap_empathy_dispatcher_chat_with_contact_id(PyObject *self, PyObject *args, PyObject *kwargs) -{ - static char *kwlist[] = { "account_id", "contact_id", NULL }; - char *account_id, *contact_id; - McAccount *account; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs,"ss:dispatcher_chat_with_contact_id", kwlist, &account_id, &contact_id)) - return NULL; - - account = mc_account_lookup (account_id); - if (account) { - empathy_dispatcher_chat_with_contact_id(account, contact_id, - NULL, NULL); - g_object_unref (account); - } - - Py_INCREF(Py_None); - return Py_None; -} -%% diff --git a/python/pyempathygtk/pyempathygtk.defs b/python/pyempathygtk/pyempathygtk.defs index 1cb19f52..df829a03 100644 --- a/python/pyempathygtk/pyempathygtk.defs +++ b/python/pyempathygtk/pyempathygtk.defs @@ -284,6 +284,12 @@ (return-type "McAccount*") ) +(define-method get_connection + (of-object "EmpathyAccountChooser") + (c-name "empathy_account_chooser_get_connection") + (return-type "TpConnection*") +) + (define-method set_account (of-object "EmpathyAccountChooser") (c-name "empathy_account_chooser_set_account") @@ -618,12 +624,6 @@ (return-type "EmpathyContact*") ) -(define-method get_members_count - (of-object "EmpathyChat") - (c-name "empathy_chat_get_members_count") - (return-type "guint") -) - (define-method get_contact_menu (of-object "EmpathyChat") (c-name "empathy_chat_get_contact_menu") @@ -966,8 +966,23 @@ (return-type "none") (parameters '("GtkWindow*" "parent") - '("gboolean" "edit") - '("gboolean" "is_user") + ) +) + +(define-method edit_dialog_show + (of-object "EmpathyContact") + (c-name "empathy_contact_edit_dialog_show") + (return-type "none") + (parameters + '("GtkWindow*" "parent") + ) +) + +(define-function contact_personal_dialog_show + (c-name "empathy_contact_personal_dialog_show") + (return-type "none") + (parameters + '("GtkWindow*" "parent") ) ) @@ -1677,21 +1692,6 @@ -;; From empathy-spell-dialog.h - -(define-function spell_dialog_show - (c-name "empathy_spell_dialog_show") - (return-type "none") - (parameters - '("EmpathyChat*" "chat") - '("GtkTextIter*" "start") - '("GtkTextIter*" "end") - '("const-gchar*" "word") - ) -) - - - ;; From empathy-theme-boxes.h (define-function theme_boxes_get_type diff --git a/python/pyempathygtk/pyempathygtk.override b/python/pyempathygtk/pyempathygtk.override index 1480cef6..3af554ec 100644 --- a/python/pyempathygtk/pyempathygtk.override +++ b/python/pyempathygtk/pyempathygtk.override @@ -29,7 +29,6 @@ headers #include "empathy-presence-chooser.h" #include "empathy-profile-chooser.h" #include "empathy-smiley-manager.h" -#include "empathy-spell-dialog.h" #include "empathy-spell.h" #include "empathy-theme-boxes.h" #include "empathy-theme-irc.h" @@ -76,6 +75,5 @@ ignore empathy_chat_correct_word empathy_chat_view_set_margin empathy_chat_get_view - empathy_spell_dialog_show empathy_window_iconify %% diff --git a/python/update-binding.sh b/python/update-binding.sh index 19c8f10b..14a5ddec 100755 --- a/python/update-binding.sh +++ b/python/update-binding.sh @@ -11,7 +11,6 @@ python /usr/share/pygobject/2.0/codegen/h2def.py \ empathy-call-factory.h \ empathy-call-handler.h \ empathy-contact.h \ - empathy-contact-factory.h \ empathy-contact-groups.h \ empathy-contact-list.h \ empathy-contact-manager.h \ @@ -34,7 +33,6 @@ python /usr/share/pygobject/2.0/codegen/h2def.py \ empathy-tp-contact-factory.h \ empathy-tp-contact-list.h \ empathy-tp-file.h \ - empathy-tp-group.h \ empathy-tp-roomlist.h \ empathy-tp-tube.h \ empathy-tube-handler.h \ @@ -78,7 +76,6 @@ python /usr/share/pygobject/2.0/codegen/h2def.py \ empathy-profile-chooser.h \ empathy-smiley-manager.h \ empathy-spell.h \ - empathy-spell-dialog.h \ empathy-theme-boxes.h \ empathy-theme-irc.h \ empathy-theme-manager.h \ diff --git a/src/empathy-accounts-dialog.c b/src/empathy-accounts-dialog.c index 036c7f86..e15c0eab 100644 --- a/src/empathy-accounts-dialog.c +++ b/src/empathy-accounts-dialog.c @@ -819,13 +819,14 @@ accounts_dialog_button_create_clicked_cb (GtkWidget *button, gchar *str; McProfileCapabilityFlags cap; - profile = empathy_profile_chooser_get_selected (dialog->combobox_profile); + profile = empathy_profile_chooser_dup_selected (dialog->combobox_profile); /* Create account */ account = mc_account_create (profile); if (account == NULL) { /* We can't display an error to the user as MC doesn't give us * any clue about the reason of the failure... */ + g_object_unref (profile); return; } @@ -869,7 +870,7 @@ accounts_dialog_profile_changed_cb (GtkWidget *widget, McProfile *profile; McProfileCapabilityFlags cap; - profile = empathy_profile_chooser_get_selected (dialog->combobox_profile); + profile = empathy_profile_chooser_dup_selected (dialog->combobox_profile); cap = mc_profile_get_capabilities (profile); if (cap & MC_PROFILE_CAPABILITY_REGISTRATION_UI) { diff --git a/src/empathy-call-window.c b/src/empathy-call-window.c index d7d79df9..49ad1414 100644 --- a/src/empathy-call-window.c +++ b/src/empathy-call-window.c @@ -107,6 +107,7 @@ struct _EmpathyCallWindowPriv GMutex *lock; gboolean call_started; + gboolean sending_video; }; #define GET_PRIV(o) \ @@ -757,6 +758,7 @@ empathy_call_window_disconnected (EmpathyCallWindow *self) gtk_widget_set_sensitive (priv->camera_button, FALSE); gtk_action_set_sensitive (priv->send_video, FALSE); + priv->sending_video = FALSE; } @@ -1157,20 +1159,35 @@ static void empathy_call_window_camera_toggled_cb (GtkToggleToolButton *toggle, EmpathyCallWindow *window) { + EmpathyCallWindowPriv *priv = GET_PRIV (window); gboolean active; active = (gtk_toggle_tool_button_get_active (toggle)); + + if (priv->sending_video == active) + return; + priv->sending_video = active; + empathy_call_window_set_send_video (window, active); + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->send_video), active); } static void empathy_call_window_send_video_toggled_cb (GtkToggleAction *toggle, EmpathyCallWindow *window) { + EmpathyCallWindowPriv *priv = GET_PRIV (window); gboolean active; active = (gtk_toggle_action_get_active (toggle)); + + if (priv->sending_video == active) + return; + priv->sending_video = active; + empathy_call_window_set_send_video (window, active); + gtk_toggle_tool_button_set_active ( + GTK_TOGGLE_TOOL_BUTTON (priv->camera_button), active); } static void diff --git a/src/empathy-call-window.ui b/src/empathy-call-window.ui index 00b8ffa8..ce3d85b5 100644 --- a/src/empathy-call-window.ui +++ b/src/empathy-call-window.ui @@ -14,6 +14,7 @@ send_video Send video + False diff --git a/src/empathy-chat-window.c b/src/empathy-chat-window.c index 145d45e7..0738f6e5 100644 --- a/src/empathy-chat-window.c +++ b/src/empathy-chat-window.c @@ -37,11 +37,11 @@ #include #include -#include #include #include #include #include +#include #include #include @@ -953,7 +953,7 @@ chat_window_new_message_cb (EmpathyChat *chat, if (has_focus && priv->current_chat == chat) { return; } - + /* If empathy_chat_is_room() returns TRUE, that means it's a named MUC. * If empathy_chat_get_remote_contact() returns NULL, that means it's * an unamed MUC (msn-like). @@ -1161,17 +1161,33 @@ chat_window_drag_data_received (GtkWidget *widget, McAccount *account; const gchar *id; gchar **strv; + const gchar *account_id; + const gchar *contact_id; id = (const gchar*) selection->data; DEBUG ("DND contact from roster with id:'%s'", id); strv = g_strsplit (id, "/", 2); - account = mc_account_lookup (strv[0]); - chat = empathy_chat_window_find_chat (account, strv[1]); + account_id = strv[0]; + contact_id = strv[1]; + account = mc_account_lookup (account_id); + chat = empathy_chat_window_find_chat (account, contact_id); if (!chat) { - empathy_dispatcher_chat_with_contact_id (account, strv[2], NULL, NULL); + EmpathyAccountManager *account_manager; + TpConnection *connection; + + account_manager = empathy_account_manager_dup_singleton (); + connection = empathy_account_manager_get_connection ( + account_manager, account); + + if (connection) { + empathy_dispatcher_chat_with_contact_id ( + connection, contact_id, NULL, NULL); + } + + g_object_unref (account_manager); g_object_unref (account); g_strfreev (strv); return; @@ -1700,17 +1716,3 @@ empathy_chat_window_present_chat (EmpathyChat *chat) gtk_widget_grab_focus (chat->input_text_view); } -#if 0 -static gboolean -chat_window_should_play_sound (EmpathyChatWindow *window) -{ - EmpathyChatWindowPriv *priv = GET_PRIV (window); - gboolean has_focus = FALSE; - - g_return_val_if_fail (EMPATHY_IS_CHAT_WINDOW (window), FALSE); - - g_object_get (priv->dialog, "has-toplevel-focus", &has_focus, NULL); - - return !has_focus; -} -#endif diff --git a/src/empathy-chatrooms-window.c b/src/empathy-chatrooms-window.c index acd559e5..fa63d5a5 100644 --- a/src/empathy-chatrooms-window.c +++ b/src/empathy-chatrooms-window.c @@ -318,7 +318,7 @@ chatrooms_window_model_refresh_data (EmpathyChatroomsWindow *window, /* Look up chatrooms */ account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser); - account = empathy_account_chooser_get_account (account_chooser); + account = empathy_account_chooser_dup_account (account_chooser); chatrooms = empathy_chatroom_manager_get_chatrooms (window->manager, account); @@ -509,7 +509,7 @@ chatrooms_window_chatroom_added_cb (EmpathyChatroomManager *manager, McAccount *account; account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser); - account = empathy_account_chooser_get_account (account_chooser); + account = empathy_account_chooser_dup_account (account_chooser); if (!account) { chatrooms_window_model_add (window, chatroom, FALSE); diff --git a/src/empathy-event-manager.c b/src/empathy-event-manager.c index adb5e73f..0b4fa775 100644 --- a/src/empathy-event-manager.c +++ b/src/empathy-event-manager.c @@ -27,10 +27,11 @@ #include #include -#include +#include #include #include #include +#include #include #include @@ -372,8 +373,7 @@ event_channel_process_voip_func (EventPriv *event) return; } - dialog = gtk_message_dialog_new (GTK_WINDOW (empathy_main_window_get()), - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, _("Incoming call")); gtk_message_dialog_format_secondary_text ( GTK_MESSAGE_DIALOG (dialog), @@ -500,21 +500,12 @@ event_manager_operation_invalidated_cb (EmpathyDispatchOperation *operation, } static void -event_manager_media_channel_got_name_cb (EmpathyContact *contact, - const GError *error, gpointer user_data, GObject *object) +event_manager_media_channel_got_contact (EventManagerApproval *approval) { - EventManagerApproval *approval = user_data; gchar *header; - if (error != NULL) - { - /* FIXME just returning assuming the operation will be invalidated as - * well */ - return; - } - header = g_strdup_printf (_("Incoming call from %s"), - empathy_contact_get_name (contact)); + empathy_contact_get_name (approval->contact)); event_manager_add (approval->manager, approval->contact, EMPATHY_IMAGE_VOIP, header, NULL, @@ -524,14 +515,6 @@ event_manager_media_channel_got_name_cb (EmpathyContact *contact, event_manager_start_ringing (approval->manager); } -static void -event_manager_media_channel_got_contact (EventManagerApproval *approval) -{ - empathy_contact_call_when_ready (approval->contact, - EMPATHY_CONTACT_READY_NAME, event_manager_media_channel_got_name_cb, - approval, NULL, G_OBJECT (approval->manager)); -} - static void event_manager_media_channel_contact_changed_cb (EmpathyTpCall *call, GParamSpec *param, EventManagerApproval *approval) @@ -604,23 +587,27 @@ event_manager_tube_dispatch_ability_cb (GObject *object, } static void -event_manager_tube_got_contact_name_cb (EmpathyContact *contact, - const GError *error, gpointer user_data, GObject *object) +event_manager_tube_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *object) { EventManagerApproval *approval = (EventManagerApproval *)user_data; EmpathyTubeDispatchAbility dispatchability; if (error != NULL) { - /* FIXME?, we assume that the operation gets invalidated as well (if it - * didn't already */ - return; + /* FIXME: We should probably still display the event */ + DEBUG ("Error: %s", error->message); + return; } + approval->contact = g_object_ref (contact); + dispatchability = empathy_tube_dispatch_is_dispatchable (approval->tube_dispatch); - switch (dispatchability) { case EMPATHY_TUBE_DISPATCHABILITY_UNKNOWN: @@ -724,10 +711,11 @@ event_room_channel_process_func (EventPriv *event) } static void -event_manager_muc_invite_got_contact_name_cb (EmpathyContact *contact, - const GError *error, - gpointer user_data, - GObject *object) +event_manager_muc_invite_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *object) { EventManagerApproval *approval = (EventManagerApproval *) user_data; TpChannel *channel; @@ -735,6 +723,14 @@ event_manager_muc_invite_got_contact_name_cb (EmpathyContact *contact, gchar *msg; TpHandle self_handle; + if (error != NULL) + { + /* FIXME: We should probably still display the event */ + DEBUG ("Error: %s", error->message); + return; + } + + approval->contact = g_object_ref (contact); channel = empathy_dispatch_operation_get_channel (approval->operation); self_handle = tp_channel_group_get_self_handle (channel); @@ -795,24 +791,20 @@ event_manager_approve_channel_cb (EmpathyDispatcher *dispatcher, channel, self_handle, &inviter, NULL, NULL)) { /* We are invited to a room */ - EmpathyContactFactory *contact_factory; - McAccount *account; + EmpathyTpContactFactory *factory; + TpConnection *connection; DEBUG ("Have been invited to %s. Ask user if he wants to accept", tp_channel_get_identifier (channel)); - account = empathy_tp_chat_get_account (tp_chat); - contact_factory = empathy_contact_factory_dup_singleton (); - - approval->contact = empathy_contact_factory_get_from_handle ( - contact_factory, account, inviter); + connection = empathy_tp_chat_get_connection (tp_chat); + factory = empathy_tp_contact_factory_dup_singleton (connection); - empathy_contact_call_when_ready (approval->contact, - EMPATHY_CONTACT_READY_NAME, - event_manager_muc_invite_got_contact_name_cb, approval, NULL, - G_OBJECT (manager)); + empathy_tp_contact_factory_get_from_handle (factory, + inviter, event_manager_muc_invite_got_contact_cb, + approval, NULL, G_OBJECT (manager)); - g_object_unref (contact_factory); + g_object_unref (factory); return; } @@ -847,73 +839,45 @@ event_manager_approve_channel_cb (EmpathyDispatcher *dispatcher, } else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER)) { - EmpathyContact *contact; - gchar *header; - TpHandle handle; - McAccount *account; - EmpathyContactFactory *factory; - TpChannel *channel = empathy_dispatch_operation_get_channel (operation); + EmpathyTpFile *file; + gchar *header; - factory = empathy_contact_factory_dup_singleton (); - handle = tp_channel_get_handle (channel, NULL); - account = empathy_channel_get_account (channel); - - contact = empathy_contact_factory_get_from_handle (factory, account, - handle); - - empathy_contact_run_until_ready (contact, - EMPATHY_CONTACT_READY_NAME, NULL); + file = EMPATHY_TP_FILE (empathy_dispatch_operation_get_channel_wrapper (operation)); + approval->contact = g_object_ref (empathy_tp_file_get_contact (file)); header = g_strdup_printf (_("Incoming file transfer from %s"), - empathy_contact_get_name (contact)); + empathy_contact_get_name (approval->contact)); - event_manager_add (manager, contact, EMPATHY_IMAGE_DOCUMENT_SEND, + event_manager_add (manager, approval->contact, EMPATHY_IMAGE_DOCUMENT_SEND, header, NULL, approval, event_channel_process_func, NULL); /* FIXME better sound for incoming file transfers ?*/ empathy_sound_play (empathy_main_window_get (), EMPATHY_SOUND_CONVERSATION_NEW); - g_object_unref (factory); - g_object_unref (account); g_free (header); } else if (!tp_strdiff (channel_type, EMP_IFACE_CHANNEL_TYPE_STREAM_TUBE) || !tp_strdiff (channel_type, EMP_IFACE_CHANNEL_TYPE_DBUS_TUBE)) { - EmpathyContact *contact; - TpHandle handle; - TpHandleType handle_type; - McAccount *account; - EmpathyContactFactory *factory; - EmpathyTubeDispatch *tube_dispatch; TpChannel *channel; + TpHandle handle; + TpHandleType handle_type; + TpConnection *connection; + EmpathyTpContactFactory *factory; channel = empathy_dispatch_operation_get_channel (operation); - handle = tp_channel_get_handle (channel, &handle_type); /* Only understand p2p tubes */ if (handle_type != TP_HANDLE_TYPE_CONTACT) return; - factory = empathy_contact_factory_dup_singleton (); - account = empathy_channel_get_account (channel); - - contact = empathy_contact_factory_get_from_handle (factory, account, - handle); - - tube_dispatch = empathy_tube_dispatch_new (operation); - - approval->contact = contact; - approval->tube_dispatch = tube_dispatch; - - empathy_contact_call_when_ready (contact, - EMPATHY_CONTACT_READY_NAME, event_manager_tube_got_contact_name_cb, - approval, NULL, G_OBJECT (manager)); - - g_object_unref (factory); - g_object_unref (account); + approval->tube_dispatch = empathy_tube_dispatch_new (operation); + connection = tp_channel_borrow_connection (channel); + factory = empathy_tp_contact_factory_dup_singleton (connection); + empathy_tp_contact_factory_get_from_handle (factory, handle, + event_manager_tube_got_contact_cb, approval, NULL, G_OBJECT (manager)); } else { @@ -945,19 +909,17 @@ event_manager_pendings_changed_cb (EmpathyContactList *list, { EventPriv *event = l->data; - if (event->public.contact == contact && - event->func == event_pending_subscribe_func) - { - event_remove (event); - break; + if (event->public.contact == contact && + event->func == event_pending_subscribe_func) + { + event_remove (event); + break; + } } - } return; } - empathy_contact_run_until_ready (contact, EMPATHY_CONTACT_READY_NAME, NULL); - header = g_strdup_printf (_("Subscription requested by %s"), empathy_contact_get_name (contact)); diff --git a/src/empathy-main-window.c b/src/empathy-main-window.c index 6c5f1fa2..b9993a8f 100644 --- a/src/empathy-main-window.c +++ b/src/empathy-main-window.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -703,23 +702,21 @@ main_window_chat_show_offline_cb (GtkToggleAction *action, static void main_window_favorite_chatroom_join (EmpathyChatroom *chatroom) { - MissionControl *mc; + EmpathyAccountManager *manager; McAccount *account; + TpConnection *connection; const gchar *room; - mc = empathy_mission_control_dup_singleton (); + manager = empathy_account_manager_dup_singleton (); account = empathy_chatroom_get_account (chatroom); + connection = empathy_account_manager_get_connection (manager, account); room = empathy_chatroom_get_room (chatroom); + g_object_unref (manager); - if (mission_control_get_connection_status (mc, account, NULL) != - TP_CONNECTION_STATUS_CONNECTED) { - return; + if (connection != NULL) { + DEBUG ("Requesting channel for '%s'", room); + empathy_dispatcher_join_muc (connection, room, NULL, NULL); } - - DEBUG ("Requesting channel for '%s'", room); - empathy_dispatcher_join_muc (account, room, NULL, NULL); - - g_object_unref (mc); } static void @@ -906,31 +903,7 @@ static void main_window_edit_personal_information_cb (GtkAction *action, EmpathyMainWindow *window) { - GSList *accounts; - - accounts = mission_control_get_online_connections (window->mc, NULL); - if (accounts) { - EmpathyContactFactory *factory; - EmpathyContact *contact; - McAccount *account; - - account = accounts->data; - factory = empathy_contact_factory_dup_singleton (); - contact = empathy_contact_factory_get_user (factory, account); - empathy_contact_run_until_ready (contact, - EMPATHY_CONTACT_READY_HANDLE | - EMPATHY_CONTACT_READY_ID, - NULL); - - empathy_contact_information_dialog_show (contact, - GTK_WINDOW (window->window), - TRUE, TRUE); - - g_slist_foreach (accounts, (GFunc) g_object_unref, NULL); - g_slist_free (accounts); - g_object_unref (factory); - g_object_unref (contact); - } + empathy_contact_personal_dialog_show (GTK_WINDOW (window->window)); } static void diff --git a/src/empathy-new-chatroom-dialog.c b/src/empathy-new-chatroom-dialog.c index bf107d1b..837d9acf 100644 --- a/src/empathy-new-chatroom-dialog.c +++ b/src/empathy-new-chatroom-dialog.c @@ -342,7 +342,7 @@ new_chatroom_dialog_update_widgets (EmpathyNewChatroomDialog *dialog) const gchar *room; account_chooser = EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser); - account = empathy_account_chooser_get_account (account_chooser); + account = empathy_account_chooser_dup_account (account_chooser); profile = mc_account_get_profile (account); protocol = mc_profile_get_protocol_name (profile); @@ -388,7 +388,7 @@ new_chatroom_dialog_account_changed_cb (GtkComboBox *combobox, new_chatroom_dialog_model_clear (dialog); account_chooser = EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser); - account = empathy_account_chooser_get_account (account_chooser); + account = empathy_account_chooser_dup_account (account_chooser); dialog->room_list = empathy_tp_roomlist_new (account); if (dialog->room_list) { @@ -409,6 +409,8 @@ new_chatroom_dialog_account_changed_cb (GtkComboBox *combobox, } new_chatroom_dialog_update_widgets (dialog); + + g_object_unref (account); } static void @@ -533,7 +535,7 @@ static void new_chatroom_dialog_join (EmpathyNewChatroomDialog *dialog) { EmpathyAccountChooser *account_chooser; - McAccount *account; + TpConnection *connection; const gchar *room; const gchar *server = NULL; gchar *room_name = NULL; @@ -542,7 +544,7 @@ new_chatroom_dialog_join (EmpathyNewChatroomDialog *dialog) server = gtk_entry_get_text (GTK_ENTRY (dialog->entry_server)); account_chooser = EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser); - account = empathy_account_chooser_get_account (account_chooser); + connection = empathy_account_chooser_get_connection (account_chooser); if (!EMP_STR_EMPTY (server)) { room_name = g_strconcat (room, "@", server, NULL); @@ -551,7 +553,7 @@ new_chatroom_dialog_join (EmpathyNewChatroomDialog *dialog) } DEBUG ("Requesting channel for '%s'", room_name); - empathy_dispatcher_join_muc (account, room_name, NULL, NULL); + empathy_dispatcher_join_muc (connection, room_name, NULL, NULL); g_free (room_name); } diff --git a/src/empathy.c b/src/empathy.c index a2115a6c..817b9bc3 100644 --- a/src/empathy.c +++ b/src/empathy.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -96,10 +97,16 @@ dispatch_cb (EmpathyDispatcher *dispatcher, } if (id) { + EmpathyAccountManager *manager; + TpConnection *connection; McAccount *account; - account = empathy_tp_chat_get_account (tp_chat); + manager = empathy_account_manager_dup_singleton (); + connection = empathy_tp_chat_get_connection (tp_chat); + account = empathy_account_manager_get_account (manager, + connection); chat = empathy_chat_window_find_chat (account, id); + g_object_unref (manager); } if (chat) { diff --git a/tests/.gitignore b/tests/.gitignore index 442cafd5..a37f3e5a 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -5,3 +5,4 @@ contact-run-until-ready-2 *.log empetit test-empathy-presence-chooser +test-empathy-status-preset-dialog diff --git a/tests/Makefile.am b/tests/Makefile.am index 67f6ec9a..7740d1f8 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -24,16 +24,14 @@ LDADD = \ noinst_PROGRAMS = \ contact-manager \ - contact-run-until-ready \ - contact-run-until-ready-2 \ empetit \ - test-empathy-presence-chooser + test-empathy-presence-chooser \ + test-empathy-status-preset-dialog contact_manager_SOURCES = contact-manager.c -contact_run_until_ready_SOURCES = contact-run-until-ready.c -contact_run_until_ready_2_SOURCES = contact-run-until-ready-2.c empetit_SOURCES = empetit.c test_empathy_presence_chooser_SOURCES = test-empathy-presence-chooser.c +test_empathy_status_preset_dialog_SOURCES = test-empathy-status-preset-dialog.c check_PROGRAMS = check-main TESTS = check-main diff --git a/tests/check-empathy-helpers.c b/tests/check-empathy-helpers.c index 2e808c0e..65273f8c 100644 --- a/tests/check-empathy-helpers.c +++ b/tests/check-empathy-helpers.c @@ -143,7 +143,7 @@ destroy_test_account (McAccount *account) error = NULL; } - gconf_entry_free (entry); + gconf_entry_unref (entry); } g_slist_free (entries); diff --git a/tests/contact-run-until-ready-2.c b/tests/contact-run-until-ready-2.c deleted file mode 100644 index 42653411..00000000 --- a/tests/contact-run-until-ready-2.c +++ /dev/null @@ -1,63 +0,0 @@ -#include - -#include -#include -#include -#include -#include - -static void -pending_cb (EmpathyContactManager *manager, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - gchar *message, - gboolean is_pending, - gpointer data) -{ - if (!is_pending) { - return; - } - - g_print ("Contact handle=%d alias=%s\n", - empathy_contact_get_handle (contact), - empathy_contact_get_name (contact)); - - empathy_contact_run_until_ready (contact, - EMPATHY_CONTACT_READY_NAME, - NULL); - - g_print ("Contact ready: handle=%d alias=%s ready=%d\n", - empathy_contact_get_handle (contact), - empathy_contact_get_name (contact), - empathy_contact_get_ready (contact)); - - g_object_unref (manager); - gtk_main_quit (); -} - -static gboolean -callback (gpointer data) -{ - EmpathyContactManager *manager; - - manager = empathy_contact_manager_dup_singleton (); - g_signal_connect (manager, "pendings-changed", - G_CALLBACK (pending_cb), - NULL); - - return FALSE; -} - -int -main (int argc, char **argv) -{ - gtk_init (&argc, &argv); - - g_idle_add (callback, NULL); - - gtk_main (); - - return EXIT_SUCCESS; -} - diff --git a/tests/contact-run-until-ready.c b/tests/contact-run-until-ready.c deleted file mode 100644 index 13fad63a..00000000 --- a/tests/contact-run-until-ready.c +++ /dev/null @@ -1,53 +0,0 @@ -#include - -#include -#include -#include -#include - -static gboolean -callback (gpointer data) -{ - EmpathyContactFactory *factory; - McAccount *account; - EmpathyContact *contact; - EmpathyContactReady ready_flags; - - factory = empathy_contact_factory_dup_singleton (); - account = mc_account_lookup ("jabber0"); - contact = empathy_contact_factory_get_from_handle (factory, account, 2); - - g_print ("Contact handle=%d alias=%s\n", - empathy_contact_get_handle (contact), - empathy_contact_get_name (contact)); - - ready_flags = EMPATHY_CONTACT_READY_HANDLE | EMPATHY_CONTACT_READY_NAME; - empathy_contact_run_until_ready (contact, ready_flags, NULL); - - g_print ("Contact ready: handle=%d alias=%s ready=%d needed-ready=%d\n", - empathy_contact_get_handle (contact), - empathy_contact_get_name (contact), - empathy_contact_get_ready (contact), - ready_flags); - - g_object_unref (factory); - g_object_unref (account); - g_object_unref (contact); - - gtk_main_quit (); - - return FALSE; -} - -int -main (int argc, char **argv) -{ - gtk_init (&argc, &argv); - - g_idle_add (callback, NULL); - - gtk_main (); - - return EXIT_SUCCESS; -} - diff --git a/tests/test-empathy-presence-chooser.c b/tests/test-empathy-presence-chooser.c index 02991e85..12d35b4c 100644 --- a/tests/test-empathy-presence-chooser.c +++ b/tests/test-empathy-presence-chooser.c @@ -24,6 +24,8 @@ #include +#include + #include #include @@ -36,6 +38,8 @@ main (int argc, char **argv) gtk_init (&argc, &argv); empathy_gtk_init (); + empathy_status_presets_get_all (); + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); chooser = empathy_presence_chooser_new (); gtk_container_add (GTK_CONTAINER (window), chooser); diff --git a/tests/test-empathy-status-preset-dialog.c b/tests/test-empathy-status-preset-dialog.c new file mode 100644 index 00000000..6602e4f2 --- /dev/null +++ b/tests/test-empathy-status-preset-dialog.c @@ -0,0 +1,49 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2009 Collabora Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Davyd Madeley + */ + +#include + +#include + +#include + +#include +#include + +int +main (int argc, char **argv) +{ + GtkWidget *dialog; + + gtk_init (&argc, &argv); + empathy_gtk_init (); + + empathy_status_presets_get_all (); + + dialog = empathy_status_preset_dialog_new (NULL); + + gtk_widget_show (dialog); + + gtk_main (); + + return 0; +}