~ubuntu-branches/ubuntu/precise/empathy/precise-proposed-201205180810

« back to all changes in this revision

Viewing changes to telepathy-yell/telepathy-yell/base-call-stream.c

  • Committer: Bazaar Package Importer
  • Author(s): Brian Curtis, Brian Curtis, Ken VanDine
  • Date: 2011-06-01 10:35:24 UTC
  • mfrom: (1.1.70 upstream) (6.3.44 experimental)
  • Revision ID: james.westby@ubuntu.com-20110601103524-wx3wgp71394730jt
Tags: 3.1.1-1ubuntu1
[ Brian Curtis ]
* Merge with Debian experimental, remaining Ubuntu changes:
* debian/control:
  - Drop geoclue/mapping build-depends (they are in Universe)
  - Add Vcz-Bzr link
  - Add Suggests on telepathy-idle
  - Bump telepathy-butterfly, telepathy-haze to recommends
  - Don't recommend the freedesktop sound theme we have an ubuntu one
  - Add build depend for libunity-dev
* debian/rules:
  - Use autoreconf.mk
  - Disable map and location
* debian/empathy.install:
  - Install message indicator configuration
* debian/indicators/empathy:
  - Message indicator configuration
* debian/patches/01_lpi.patch:
  - Add Launchpad integration
* debian/patches/10_use_notify_osd_icons.patch:
  - Use the notify-osd image for new messages
* debian/patches/34_start_raised_execpt_in_session.patch
  - If not started with the session, we should always raise
* debian/patches/36_chat_window_default_size.patch:
  - Make the default chat window size larger
* debian/patches/37_facebook_default.patch:
  - Make facebook the default chat account type
* debian/patches/38_lp_569289.patch
  - Set freenode as default IRC network for new IRC accounts 
* debian/patches/41_unity_launcher_progress.patch
  - Display file transfer progress in the unity launcher

[ Ken VanDine ]
* debian/control
  - build depend on libgcr-3-dev instead of libgcr-dev
  - dropped build depends for libindicate, we will use telepathy-indicator
  - Depend on dconf-gsettings-backend | gsettings-backend
  - Added a Recommends for telepathy-indicator
* +debian/empathy.gsettings-override
  - Added an override for notifications-focus
* debian/patches/series
  - commented out 23_idomessagedialog_for_voip_and_ft.patch, until ido has 
    been ported to gtk3

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * base-call-stream.c - Source for TpyBaseCallStream
3
 
 * Copyright © 2009–2010 Collabora Ltd.
4
 
 * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk>
5
 
 * @author Will Thompson <will.thompson@collabora.co.uk>
6
 
 *
7
 
 * This library is free software; you can redistribute it and/or
8
 
 * modify it under the terms of the GNU Lesser General Public
9
 
 * License as published by the Free Software Foundation; either
10
 
 * version 2.1 of the License, or (at your option) any later version.
11
 
 *
12
 
 * This library is distributed in the hope that it will be useful,
13
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 
 * Lesser General Public License for more details.
16
 
 *
17
 
 * You should have received a copy of the GNU Lesser General Public
18
 
 * License along with this library; if not, write to the Free Software
19
 
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20
 
 */
21
 
 
22
 
#include "base-call-stream.h"
23
 
 
24
 
#define DEBUG_FLAG TPY_DEBUG_CALL
25
 
#include "debug.h"
26
 
 
27
 
#include <telepathy-yell/interfaces.h>
28
 
#include <telepathy-yell/gtypes.h>
29
 
#include <telepathy-yell/svc-call.h>
30
 
 
31
 
static void call_stream_iface_init (gpointer g_iface, gpointer iface_data);
32
 
 
33
 
G_DEFINE_TYPE_WITH_CODE(TpyBaseCallStream, tpy_base_call_stream,
34
 
    G_TYPE_OBJECT,
35
 
    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
36
 
        tp_dbus_properties_mixin_iface_init);
37
 
    G_IMPLEMENT_INTERFACE (TPY_TYPE_SVC_CALL_STREAM, call_stream_iface_init);
38
 
    )
39
 
 
40
 
enum
41
 
{
42
 
  PROP_OBJECT_PATH = 1,
43
 
  PROP_CONNECTION,
44
 
 
45
 
  /* Call interface properties */
46
 
  PROP_INTERFACES,
47
 
  PROP_REMOTE_MEMBERS,
48
 
  PROP_LOCAL_SENDING_STATE,
49
 
  PROP_CAN_REQUEST_RECEIVING,
50
 
};
51
 
 
52
 
struct _TpyBaseCallStreamPrivate
53
 
{
54
 
  gboolean dispose_has_run;
55
 
 
56
 
  gchar *object_path;
57
 
  TpBaseConnection *conn;
58
 
 
59
 
  GHashTable *remote_members;
60
 
 
61
 
  TpySendingState local_sending_state;
62
 
};
63
 
 
64
 
static void
65
 
tpy_base_call_stream_init (TpyBaseCallStream *self)
66
 
{
67
 
  TpyBaseCallStreamPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
68
 
      TPY_TYPE_BASE_CALL_STREAM, TpyBaseCallStreamPrivate);
69
 
 
70
 
  self->priv = priv;
71
 
  priv->remote_members = g_hash_table_new (g_direct_hash, g_direct_equal);
72
 
}
73
 
 
74
 
static void
75
 
tpy_base_call_stream_constructed (GObject *obj)
76
 
{
77
 
  TpyBaseCallStream *self = TPY_BASE_CALL_STREAM (obj);
78
 
  TpyBaseCallStreamPrivate *priv = self->priv;
79
 
  TpDBusDaemon *bus = tp_base_connection_get_dbus_daemon (
80
 
      (TpBaseConnection *) priv->conn);
81
 
 
82
 
  if (G_OBJECT_CLASS (tpy_base_call_stream_parent_class)->constructed
83
 
      != NULL)
84
 
    G_OBJECT_CLASS (tpy_base_call_stream_parent_class)->constructed (obj);
85
 
 
86
 
  priv->local_sending_state = TPY_SENDING_STATE_NONE;
87
 
 
88
 
  /* register object on the bus */
89
 
  DEBUG ("Registering %s", priv->object_path);
90
 
  tp_dbus_daemon_register_object (bus, priv->object_path, obj);
91
 
}
92
 
 
93
 
static void
94
 
tpy_base_call_stream_dispose (GObject *object)
95
 
{
96
 
  TpyBaseCallStream *self = TPY_BASE_CALL_STREAM (object);
97
 
  TpyBaseCallStreamPrivate *priv = self->priv;
98
 
 
99
 
  if (priv->dispose_has_run)
100
 
    return;
101
 
 
102
 
  priv->dispose_has_run = TRUE;
103
 
 
104
 
  tp_clear_object (&priv->conn);
105
 
 
106
 
  if (G_OBJECT_CLASS (tpy_base_call_stream_parent_class)->dispose != NULL)
107
 
    G_OBJECT_CLASS (tpy_base_call_stream_parent_class)->dispose (object);
108
 
}
109
 
 
110
 
static void
111
 
tpy_base_call_stream_finalize (GObject *object)
112
 
{
113
 
  TpyBaseCallStream *self = TPY_BASE_CALL_STREAM (object);
114
 
  TpyBaseCallStreamPrivate *priv = self->priv;
115
 
 
116
 
  /* free any data held directly by the object here */
117
 
  g_free (priv->object_path);
118
 
  g_hash_table_destroy (priv->remote_members);
119
 
 
120
 
  if (G_OBJECT_CLASS (tpy_base_call_stream_parent_class)->finalize != NULL)
121
 
    G_OBJECT_CLASS (tpy_base_call_stream_parent_class)->finalize (object);
122
 
}
123
 
 
124
 
static void
125
 
tpy_base_call_stream_get_property (
126
 
    GObject *object,
127
 
    guint property_id,
128
 
    GValue *value,
129
 
    GParamSpec *pspec)
130
 
{
131
 
  TpyBaseCallStream *self = TPY_BASE_CALL_STREAM (object);
132
 
  TpyBaseCallStreamPrivate *priv = self->priv;
133
 
 
134
 
  switch (property_id)
135
 
    {
136
 
      case PROP_CONNECTION:
137
 
        g_value_set_object (value, priv->conn);
138
 
        break;
139
 
      case PROP_OBJECT_PATH:
140
 
        g_value_set_string (value, priv->object_path);
141
 
        break;
142
 
      case PROP_REMOTE_MEMBERS:
143
 
        g_value_set_boxed (value, priv->remote_members);
144
 
        break;
145
 
      case PROP_LOCAL_SENDING_STATE:
146
 
        g_value_set_uint (value, priv->local_sending_state);
147
 
        break;
148
 
      case PROP_CAN_REQUEST_RECEIVING:
149
 
        {
150
 
          TpyBaseCallStreamClass *klass =
151
 
              TPY_BASE_CALL_STREAM_GET_CLASS (self);
152
 
 
153
 
          g_value_set_boolean (value, klass->request_receiving != NULL);
154
 
          break;
155
 
        }
156
 
      case PROP_INTERFACES:
157
 
        {
158
 
          TpyBaseCallStreamClass *klass =
159
 
              TPY_BASE_CALL_STREAM_GET_CLASS (self);
160
 
 
161
 
          if (klass->extra_interfaces != NULL)
162
 
            {
163
 
              g_value_set_boxed (value, klass->extra_interfaces);
164
 
            }
165
 
          else
166
 
            {
167
 
              gchar *empty[] = { NULL };
168
 
 
169
 
              g_value_set_boxed (value, empty);
170
 
            }
171
 
          break;
172
 
        }
173
 
      default:
174
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
175
 
        break;
176
 
    }
177
 
}
178
 
 
179
 
static void
180
 
tpy_base_call_stream_set_property (
181
 
    GObject *object,
182
 
    guint property_id,
183
 
    const GValue *value,
184
 
    GParamSpec *pspec)
185
 
{
186
 
  TpyBaseCallStream *self = TPY_BASE_CALL_STREAM (object);
187
 
  TpyBaseCallStreamPrivate *priv = self->priv;
188
 
 
189
 
  switch (property_id)
190
 
    {
191
 
      case PROP_CONNECTION:
192
 
        priv->conn = g_value_dup_object (value);
193
 
        g_assert (priv->conn != NULL);
194
 
        break;
195
 
      case PROP_OBJECT_PATH:
196
 
        g_free (priv->object_path);
197
 
        priv->object_path = g_value_dup_string (value);
198
 
        break;
199
 
      case PROP_LOCAL_SENDING_STATE:
200
 
        self->priv->local_sending_state = g_value_get_uint (value);
201
 
        break;
202
 
      default:
203
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
204
 
        break;
205
 
    }
206
 
}
207
 
 
208
 
static void
209
 
tpy_base_call_stream_class_init (TpyBaseCallStreamClass *bsc_class)
210
 
{
211
 
  GObjectClass *object_class = G_OBJECT_CLASS (bsc_class);
212
 
  GParamSpec *param_spec;
213
 
  static TpDBusPropertiesMixinPropImpl stream_props[] = {
214
 
    { "Interfaces", "interfaces", NULL },
215
 
    { "RemoteMembers", "remote-members", NULL },
216
 
    { "LocalSendingState", "local-sending-state", NULL },
217
 
    { "CanRequestReceiving", "can-request-receiving", NULL },
218
 
    { NULL }
219
 
  };
220
 
  static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
221
 
      { TPY_IFACE_CALL_STREAM,
222
 
        tp_dbus_properties_mixin_getter_gobject_properties,
223
 
        NULL,
224
 
        stream_props,
225
 
      },
226
 
      { NULL }
227
 
  };
228
 
 
229
 
  g_type_class_add_private (bsc_class, sizeof (TpyBaseCallStreamPrivate));
230
 
 
231
 
  object_class->constructed = tpy_base_call_stream_constructed;
232
 
  object_class->dispose = tpy_base_call_stream_dispose;
233
 
  object_class->finalize = tpy_base_call_stream_finalize;
234
 
  object_class->set_property = tpy_base_call_stream_set_property;
235
 
  object_class->get_property = tpy_base_call_stream_get_property;
236
 
 
237
 
  param_spec = g_param_spec_object ("connection", "TpBaseConnection object",
238
 
      "Tpy connection object that owns this call stream",
239
 
      TP_TYPE_BASE_CONNECTION,
240
 
      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
241
 
  g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
242
 
 
243
 
  param_spec = g_param_spec_string ("object-path", "D-Bus object path",
244
 
      "The D-Bus object path used for this "
245
 
      "object on the bus.",
246
 
      NULL,
247
 
      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
248
 
  g_object_class_install_property (object_class, PROP_OBJECT_PATH, param_spec);
249
 
 
250
 
  param_spec = g_param_spec_boxed ("interfaces", "Interfaces",
251
 
      "Stream interfaces",
252
 
      G_TYPE_STRV,
253
 
      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
254
 
  g_object_class_install_property (object_class, PROP_INTERFACES,
255
 
      param_spec);
256
 
 
257
 
  param_spec = g_param_spec_boxed ("remote-members", "Remote members",
258
 
      "Remote member map",
259
 
      TPY_HASH_TYPE_CONTACT_SENDING_STATE_MAP,
260
 
      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
261
 
  g_object_class_install_property (object_class, PROP_REMOTE_MEMBERS,
262
 
      param_spec);
263
 
 
264
 
  param_spec = g_param_spec_uint ("local-sending-state", "LocalSendingState",
265
 
      "Local sending state",
266
 
      0, NUM_TPY_SENDING_STATES, 0,
267
 
      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
268
 
  g_object_class_install_property (object_class, PROP_LOCAL_SENDING_STATE,
269
 
      param_spec);
270
 
 
271
 
  param_spec = g_param_spec_boolean ("can-request-receiving",
272
 
      "CanRequestReceiving",
273
 
      "If true, the user can request that a remote contact starts sending on"
274
 
      "this stream.",
275
 
      FALSE,
276
 
      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
277
 
  g_object_class_install_property (object_class, PROP_CAN_REQUEST_RECEIVING,
278
 
      param_spec);
279
 
 
280
 
  bsc_class->dbus_props_class.interfaces = prop_interfaces;
281
 
  tp_dbus_properties_mixin_class_init (object_class,
282
 
      G_STRUCT_OFFSET (TpyBaseCallStreamClass, dbus_props_class));
283
 
}
284
 
 
285
 
TpBaseConnection *
286
 
tpy_base_call_stream_get_connection (TpyBaseCallStream *self)
287
 
{
288
 
  g_return_val_if_fail (TPY_IS_BASE_CALL_STREAM (self), NULL);
289
 
 
290
 
  return self->priv->conn;
291
 
}
292
 
 
293
 
const gchar *
294
 
tpy_base_call_stream_get_object_path (TpyBaseCallStream *self)
295
 
{
296
 
  g_return_val_if_fail (TPY_IS_BASE_CALL_STREAM (self), NULL);
297
 
 
298
 
  return self->priv->object_path;
299
 
}
300
 
 
301
 
static gboolean
302
 
_remote_member_update_state (TpyBaseCallStream *self,
303
 
    TpHandle contact,
304
 
    TpySendingState state)
305
 
{
306
 
  TpyBaseCallStreamPrivate *priv = self->priv;
307
 
  gpointer state_p = 0;
308
 
  gboolean exists;
309
 
 
310
 
  exists = g_hash_table_lookup_extended (priv->remote_members,
311
 
    GUINT_TO_POINTER (contact),
312
 
    NULL,
313
 
    &state_p);
314
 
 
315
 
  if (exists && GPOINTER_TO_UINT (state_p) == state)
316
 
    return FALSE;
317
 
 
318
 
  DEBUG ("Updating remote member %d state: %d => %d", contact,
319
 
    GPOINTER_TO_UINT (state_p), state);
320
 
 
321
 
  g_hash_table_insert (priv->remote_members,
322
 
    GUINT_TO_POINTER (contact),
323
 
    GUINT_TO_POINTER (state));
324
 
 
325
 
  return TRUE;
326
 
}
327
 
 
328
 
gboolean
329
 
tpy_base_call_stream_update_remote_member_states (TpyBaseCallStream *self,
330
 
      TpHandle peer, TpySendingState remote_state,
331
 
      ...)
332
 
{
333
 
  GHashTable *updates = g_hash_table_new (g_direct_hash, g_direct_equal);
334
 
  gboolean updated = FALSE;
335
 
  va_list args;
336
 
 
337
 
  va_start (args, remote_state);
338
 
 
339
 
  do
340
 
    {
341
 
      if (_remote_member_update_state (self, peer, remote_state))
342
 
        {
343
 
          g_hash_table_insert (updates,
344
 
              GUINT_TO_POINTER (peer),
345
 
              GUINT_TO_POINTER (remote_state));
346
 
          updated = TRUE;
347
 
        }
348
 
 
349
 
      peer = va_arg (args, TpHandle);
350
 
      if (peer != 0)
351
 
        remote_state = va_arg (args, TpySendingState);
352
 
    }
353
 
  while (peer != 0);
354
 
 
355
 
  if (updated)
356
 
    {
357
 
      GArray *empty = g_array_new (FALSE, TRUE, sizeof (TpHandle));
358
 
 
359
 
      tpy_svc_call_stream_emit_remote_members_changed (self, updates, empty);
360
 
      g_array_unref (empty);
361
 
    }
362
 
 
363
 
  g_hash_table_unref (updates);
364
 
  return updated;
365
 
}
366
 
 
367
 
gboolean
368
 
tpy_base_call_stream_remove_member (TpyBaseCallStream *self,
369
 
    TpHandle removed)
370
 
{
371
 
  GArray *removed_array;
372
 
  GHashTable *empty;
373
 
 
374
 
  if (!g_hash_table_remove (self->priv->remote_members,
375
 
      GUINT_TO_POINTER(removed)))
376
 
    return FALSE;
377
 
 
378
 
  empty= g_hash_table_new (g_direct_hash, g_direct_equal);
379
 
  removed_array = g_array_sized_new (FALSE, TRUE, sizeof (TpHandle), 1);
380
 
  g_array_append_val (removed_array, removed);
381
 
 
382
 
  tpy_svc_call_stream_emit_remote_members_changed (self, empty, removed_array);
383
 
 
384
 
  g_hash_table_unref (empty);
385
 
  g_array_free (removed_array, TRUE);
386
 
  return TRUE;
387
 
}
388
 
 
389
 
TpySendingState
390
 
tpy_base_call_stream_get_local_sending_state (
391
 
  TpyBaseCallStream *self)
392
 
{
393
 
  return self->priv->local_sending_state;
394
 
}
395
 
 
396
 
gboolean
397
 
tpy_base_call_stream_update_local_sending_state (TpyBaseCallStream *self,
398
 
    TpySendingState state)
399
 
{
400
 
  TpyBaseCallStreamPrivate *priv = self->priv;
401
 
 
402
 
  if (priv->local_sending_state == state)
403
 
    return FALSE;
404
 
 
405
 
  priv->local_sending_state = state;
406
 
  g_object_notify (G_OBJECT (self), "local-sending-state");
407
 
 
408
 
  tpy_svc_call_stream_emit_local_sending_state_changed (
409
 
    TPY_SVC_CALL_STREAM (self), state);
410
 
 
411
 
  return TRUE;
412
 
}
413
 
 
414
 
gboolean
415
 
tpy_base_call_stream_set_sending (TpyBaseCallStream *self,
416
 
  gboolean send,
417
 
  GError **error)
418
 
{
419
 
  TpyBaseCallStreamPrivate *priv = self->priv;
420
 
  TpyBaseCallStreamClass *klass = TPY_BASE_CALL_STREAM_GET_CLASS (self);
421
 
 
422
 
  /* Determine if there is a state change for our sending side */
423
 
  switch (priv->local_sending_state)
424
 
    {
425
 
      case TPY_SENDING_STATE_NONE:
426
 
      case TPY_SENDING_STATE_PENDING_SEND:
427
 
        if (!send)
428
 
          goto out;
429
 
        break;
430
 
      case TPY_SENDING_STATE_SENDING:
431
 
      case TPY_SENDING_STATE_PENDING_STOP_SENDING:
432
 
        if (send)
433
 
          goto out;
434
 
        break;
435
 
      default:
436
 
        g_assert_not_reached ();
437
 
    }
438
 
 
439
 
  if (klass->set_sending != NULL)
440
 
    {
441
 
      if (!klass->set_sending (self, send, error))
442
 
        goto failed;
443
 
    }
444
 
  else
445
 
    {
446
 
      g_set_error_literal (error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED,
447
 
        "This CM does not implement SetSending");
448
 
      goto failed;
449
 
    }
450
 
 
451
 
out:
452
 
  tpy_base_call_stream_update_local_sending_state (self,
453
 
    send ? TPY_SENDING_STATE_SENDING : TPY_SENDING_STATE_NONE);
454
 
  return TRUE;
455
 
 
456
 
failed:
457
 
  return FALSE;
458
 
}
459
 
 
460
 
static void
461
 
tpy_base_call_stream_set_sending_dbus (TpySvcCallStream *iface,
462
 
    gboolean sending,
463
 
    DBusGMethodInvocation *context)
464
 
{
465
 
  GError *error = NULL;
466
 
 
467
 
  if (tpy_base_call_stream_set_sending (TPY_BASE_CALL_STREAM (iface),
468
 
      sending, &error))
469
 
    tpy_svc_call_stream_return_from_set_sending (context);
470
 
  else
471
 
    dbus_g_method_return_error (context, error);
472
 
 
473
 
  g_clear_error (&error);
474
 
}
475
 
 
476
 
static void
477
 
tpy_base_call_stream_request_receiving (TpySvcCallStream *iface,
478
 
    TpHandle handle,
479
 
    gboolean receiving,
480
 
    DBusGMethodInvocation *context)
481
 
{
482
 
  GError *error = NULL;
483
 
  TpyBaseCallStream *self = TPY_BASE_CALL_STREAM (iface);
484
 
  TpyBaseCallStreamClass *klass = TPY_BASE_CALL_STREAM_GET_CLASS (self);
485
 
 
486
 
  if (klass->request_receiving != NULL)
487
 
    klass->request_receiving (self, handle, receiving, &error);
488
 
  else
489
 
    g_set_error_literal (&error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED,
490
 
        "This CM does not implement request_receiving");
491
 
 
492
 
  if (error != NULL)
493
 
    dbus_g_method_return_error (context, error);
494
 
  else
495
 
    tpy_svc_call_stream_return_from_request_receiving (context);
496
 
 
497
 
  g_clear_error (&error);
498
 
}
499
 
 
500
 
static void
501
 
call_stream_iface_init (gpointer g_iface, gpointer iface_data)
502
 
{
503
 
  TpySvcCallStreamClass *klass =
504
 
    (TpySvcCallStreamClass *) g_iface;
505
 
 
506
 
#define IMPLEMENT(x, suffix) tpy_svc_call_stream_implement_##x (\
507
 
    klass, tpy_base_call_stream_##x##suffix)
508
 
  IMPLEMENT(set_sending, _dbus);
509
 
  IMPLEMENT(request_receiving,);
510
 
#undef IMPLEMENT
511
 
}