tizen: release 0.0.4
[platform/core/system/tlm.git] / src / daemon / tlm-dbus-observer.c
1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4  * This file is part of tlm (Tizen Login Manager)
5  *
6  * Copyright (C) 2014 Intel Corporation.
7  *
8  * Contact: Imran Zaman <imran.zaman@intel.com>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23  * 02110-1301 USA
24  */
25
26 #include <string.h>
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <grp.h>
32 #include <stdio.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35
36 #include "tlm-dbus-observer.h"
37 #include "tlm-log.h"
38 #include "tlm-utils.h"
39 #include "dbus/tlm-dbus-server-interface.h"
40 #include "dbus/tlm-dbus-server-p2p.h"
41 #include "dbus/tlm-dbus-login-adapter.h"
42 #include "dbus/tlm-dbus-utils.h"
43 #include "tlm-seat.h"
44 #include "tlm-manager.h"
45 #include "common/tlm-error.h"
46
47 G_DEFINE_TYPE (TlmDbusObserver, tlm_dbus_observer, G_TYPE_OBJECT);
48
49 #define TLM_DBUS_OBSERVER_PRIV(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
50             TLM_TYPE_DBUS_OBSERVER, TlmDbusObserverPrivate)
51
52 typedef struct
53 {
54     TlmDbusRequest *dbus_request;
55     TlmSeat *seat;
56 } TlmRequest;
57
58 struct _TlmDbusObserverPrivate
59 {
60     TlmManager *manager;
61     TlmSeat *seat;
62     TlmDbusServer *dbus_server;
63     GQueue *request_queue;
64     guint request_id;
65     TlmRequest *active_request;
66     DbusObserverEnableFlags enable_flags;
67 };
68
69 static void
70 _handle_dbus_client_added (
71         TlmDbusObserver *self,
72         GObject *dbus_adapter,
73         GObject *dbus_server);
74
75 static void
76 _handle_dbus_client_removed (
77         TlmDbusObserver *self,
78         GObject *dbus_adapter,
79         GObject *dbus_server);
80
81 static void
82 _handle_dbus_login_user (
83         TlmDbusObserver *self,
84         const gchar *seat_id,
85         const gchar *username,
86         const gchar *password,
87         GVariant *environment,
88         GDBusMethodInvocation *invocation,
89         GObject *dbus_adapter);
90
91 static void
92 _handle_dbus_logout_user (
93         TlmDbusObserver *self,
94         const gchar *seat_id,
95         GDBusMethodInvocation *invocation,
96         GObject *dbus_adapter);
97
98 static void
99 _handle_dbus_switch_user (
100         TlmDbusObserver *self,
101         const gchar *seat_id,
102         const gchar *username,
103         const gchar *password,
104         GVariant *environment,
105         GDBusMethodInvocation *invocation,
106         GObject *dbus_adapter);
107
108 static void
109 _disconnect_dbus_adapter (
110         TlmDbusObserver *self,
111         TlmDbusLoginAdapter *adapter);
112
113 static void
114 _handle_seat_session_created (
115         TlmDbusObserver *self,
116         const gchar *seat_id,
117         GObject *seat);
118
119 static gboolean
120 _handle_seat_session_terminated (
121         TlmDbusObserver *self,
122         const gchar *seat_id,
123         GObject *seat);
124
125 static void
126 _handle_seat_session_error (
127         TlmDbusObserver *self,
128         TlmError error,
129         GObject *seat);
130
131 static void
132 _disconnect_seat (
133         TlmDbusObserver *self,
134         TlmSeat *seat);
135
136 static void
137 _connect_seat (
138         TlmDbusObserver *self,
139         TlmSeat *seat);
140
141 static void
142 _process_next_request_in_idle (
143         TlmDbusObserver *self);
144
145 static void
146 _on_seat_dispose (
147         TlmDbusObserver *self,
148         GObject *dead)
149 {
150     g_return_if_fail (self && TLM_IS_DBUS_OBSERVER(self) && dead &&
151                 TLM_IS_SEAT(dead));
152     g_object_weak_unref (dead, (GWeakNotify)_on_seat_dispose, self);
153     _disconnect_seat (self, TLM_SEAT (dead));
154     if (self->priv->active_request &&
155         G_OBJECT(self->priv->active_request->seat) == dead) {
156         self->priv->active_request->seat = NULL;
157     }
158     if (G_OBJECT(self->priv->seat) == dead)
159         self->priv->seat = NULL;
160 }
161
162 static void
163 _on_manager_dispose (
164         TlmDbusObserver *self,
165         GObject *dead)
166 {
167     g_return_if_fail (self && TLM_IS_DBUS_OBSERVER(self) && dead &&
168                 TLM_IS_MANAGER(dead));
169     g_object_weak_unref (dead, (GWeakNotify)_on_manager_dispose, self);
170     self->priv->manager = NULL;
171 }
172
173 static TlmRequest *
174 _create_request (
175         TlmDbusObserver *self,
176         TlmDbusRequest *dbus_req,
177         TlmSeat *seat)
178 {
179     TlmRequest *request = g_malloc0 (sizeof (TlmRequest));
180     if (!request) return NULL;
181
182     request->dbus_request = dbus_req;
183     request->seat = seat;
184     if (request->seat) {
185         _connect_seat (self, request->seat);
186         g_object_weak_ref (G_OBJECT (request->seat),
187                 (GWeakNotify)_on_seat_dispose, self);
188     }
189     return request;
190 }
191
192 static void
193 _dispose_request (
194         TlmDbusObserver *self,
195         TlmRequest *request)
196 {
197     if (!request) return;
198
199     if (request->dbus_request) {
200         tlm_dbus_login_adapter_request_completed (request->dbus_request, NULL);
201         tlm_dbus_utils_dispose_request (request->dbus_request);
202         request->dbus_request = NULL;
203     }
204     if (request->seat) {
205         _disconnect_seat (self, request->seat);
206         g_object_weak_unref (G_OBJECT (request->seat),
207                 (GWeakNotify)_on_seat_dispose, self);
208         request->seat = NULL;
209     }
210     g_free (request);
211 }
212
213 static void
214 _disconnect_seat (
215         TlmDbusObserver *self,
216         TlmSeat *seat)
217 {
218     DBG ("self %p seat %p", self, seat);
219     if (!seat) return;
220
221     g_signal_handlers_disconnect_by_func (G_OBJECT (seat),
222             _handle_seat_session_created, self);
223     g_signal_handlers_disconnect_by_func (G_OBJECT (seat),
224             _handle_seat_session_terminated, self);
225     g_signal_handlers_disconnect_by_func (G_OBJECT (seat),
226             _handle_seat_session_error, self);
227 }
228
229 static void
230 _connect_seat (
231         TlmDbusObserver *self,
232         TlmSeat *seat)
233 {
234     DBG ("self %p seat %p", self, seat);
235     if (!seat) return;
236
237     g_signal_connect_swapped (G_OBJECT (seat), "session-created",
238             G_CALLBACK(_handle_seat_session_created), self);
239     g_signal_connect_swapped (G_OBJECT (seat), "session-terminated",
240             G_CALLBACK(_handle_seat_session_terminated), self);
241     g_signal_connect_swapped (G_OBJECT (seat), "session-error",
242             G_CALLBACK(_handle_seat_session_error), self);
243 }
244
245 static void
246 _on_dbus_adapter_dispose (
247         TlmDbusObserver *self,
248         GObject *dead)
249 {
250     GList *head=NULL, *elem=NULL, *next;
251
252     g_return_if_fail (self && TLM_IS_DBUS_OBSERVER(self) && dead &&
253                 TLM_IS_DBUS_LOGIN_ADAPTER(dead));
254     _disconnect_dbus_adapter (self, TLM_DBUS_LOGIN_ADAPTER(dead));
255
256     if (self->priv->request_queue)
257         head = elem = g_queue_peek_head_link (self->priv->request_queue);
258     while (elem) {
259         TlmRequest *request = elem->data;
260         TlmDbusRequest *dbus_req = request->dbus_request;
261         next = g_list_next (elem);
262         if (dbus_req && G_OBJECT (dbus_req->dbus_adapter) == dead) {
263             DBG ("removing the request for dead dbus adapter");
264             head = g_list_delete_link (head, elem);
265             _dispose_request (self, request);
266         }
267         elem = next;
268     }
269
270     /* check for active request */
271     if (self->priv->active_request &&
272         G_OBJECT (self->priv->active_request->dbus_request->dbus_adapter) ==
273                 dead) {
274         DBG ("removing the request for dead dbus adapter");
275         _dispose_request (self, self->priv->active_request);
276         self->priv->active_request = NULL;
277         if (self->priv->request_id) {
278             g_source_remove (self->priv->request_id);
279             self->priv->request_id = 0;
280         }
281         _process_next_request_in_idle (self);
282     }
283 }
284
285 static void
286 _connect_dbus_adapter (
287         TlmDbusObserver *self,
288         TlmDbusLoginAdapter *adapter)
289 {
290     if (self->priv->enable_flags & DBUS_OBSERVER_ENABLE_LOGIN_USER)
291         g_signal_connect_swapped (G_OBJECT (adapter),
292                 "login-user", G_CALLBACK(_handle_dbus_login_user), self);
293     if (self->priv->enable_flags & DBUS_OBSERVER_ENABLE_LOGOUT_USER)
294         g_signal_connect_swapped (G_OBJECT (adapter),
295                 "logout-user", G_CALLBACK(_handle_dbus_logout_user), self);
296     if (self->priv->enable_flags & DBUS_OBSERVER_ENABLE_SWITCH_USER)
297         g_signal_connect_swapped (G_OBJECT (adapter),
298                 "switch-user", G_CALLBACK(_handle_dbus_switch_user), self);
299 }
300
301 static void
302 _disconnect_dbus_adapter (
303         TlmDbusObserver *self,
304         TlmDbusLoginAdapter *adapter)
305 {
306     if (self->priv->enable_flags & DBUS_OBSERVER_ENABLE_LOGIN_USER)
307         g_signal_handlers_disconnect_by_func (G_OBJECT(adapter),
308                 _handle_dbus_login_user, self);
309     if (self->priv->enable_flags & DBUS_OBSERVER_ENABLE_LOGOUT_USER)
310         g_signal_handlers_disconnect_by_func (G_OBJECT(adapter),
311                 _handle_dbus_logout_user, self);
312     if (self->priv->enable_flags & DBUS_OBSERVER_ENABLE_SWITCH_USER)
313         g_signal_handlers_disconnect_by_func (G_OBJECT(adapter),
314                 _handle_dbus_switch_user, self);
315 }
316
317 static void
318 _handle_dbus_client_added (
319         TlmDbusObserver *self,
320         GObject *dbus_adapter,
321         GObject *dbus_server)
322 {
323     g_return_if_fail (self && TLM_IS_DBUS_OBSERVER(self) && dbus_adapter &&
324             TLM_IS_DBUS_LOGIN_ADAPTER(dbus_adapter));
325     _connect_dbus_adapter (self, TLM_DBUS_LOGIN_ADAPTER(dbus_adapter));
326     g_object_weak_ref (G_OBJECT (dbus_adapter),
327             (GWeakNotify)_on_dbus_adapter_dispose, self);
328 }
329
330 static void
331 _handle_dbus_client_removed (
332         TlmDbusObserver *self,
333         GObject *dbus_adapter,
334         GObject *dbus_server)
335 {
336     g_return_if_fail (self && TLM_IS_DBUS_OBSERVER(self) && dbus_adapter &&
337             TLM_IS_DBUS_LOGIN_ADAPTER(dbus_adapter));
338     _disconnect_dbus_adapter (self, TLM_DBUS_LOGIN_ADAPTER(dbus_adapter));
339     g_object_weak_unref (G_OBJECT (dbus_adapter),
340             (GWeakNotify)_on_dbus_adapter_dispose, self);
341 }
342
343 static void
344 _complete_dbus_request (
345         TlmDbusRequest *request,
346         GError *error)
347 {
348     if (request) {
349         tlm_dbus_login_adapter_request_completed (request, error);
350         tlm_dbus_utils_dispose_request (request);
351     }
352     if (error) g_error_free (error);
353 }
354
355 static void
356 _abort_dbus_request (
357         TlmDbusRequest *request)
358 {
359         if (!request) return;
360
361         GError *error = TLM_GET_ERROR_FOR_ID (TLM_ERROR_DBUS_REQ_ABORTED,
362             "Dbus request aborted");
363     _complete_dbus_request (request, error);
364 }
365
366 static void
367 _complete_request (
368                 TlmDbusObserver *self,
369         TlmRequest *request,
370         GError *error)
371 {
372     _complete_dbus_request (request->dbus_request, error);
373         request->dbus_request = NULL;
374     _dispose_request (self, request);
375 }
376
377 static void
378 _clear_request (
379         TlmRequest *request,
380         TlmDbusObserver *self)
381 {
382         if (!request) return;
383
384         _abort_dbus_request (request->dbus_request);
385         request->dbus_request = NULL;
386         _dispose_request (self, request);
387 }
388
389 static gboolean
390 _is_request_supported (
391         TlmDbusObserver *self,
392         TlmDbusRequestType req_type)
393 {
394     switch (req_type) {
395     case TLM_DBUS_REQUEST_TYPE_LOGIN_USER:
396         return (self->priv->enable_flags & DBUS_OBSERVER_ENABLE_LOGIN_USER);
397     case TLM_DBUS_REQUEST_TYPE_LOGOUT_USER:
398         return (self->priv->enable_flags & DBUS_OBSERVER_ENABLE_LOGOUT_USER);
399     case TLM_DBUS_REQUEST_TYPE_SWITCH_USER:
400         return (self->priv->enable_flags & DBUS_OBSERVER_ENABLE_SWITCH_USER);
401     }
402     return FALSE;
403 }
404
405 static gboolean
406 _process_request (
407         TlmDbusObserver *self)
408 {
409     g_return_val_if_fail (self && TLM_IS_DBUS_OBSERVER(self), FALSE);
410     GError *err = NULL;
411     TlmRequest* req = NULL;
412     TlmDbusRequest* dbus_req = NULL;
413     TlmSeat *seat = NULL;
414
415     self->priv->request_id = 0;
416
417     if (!self->priv->active_request) {
418         gboolean ret = FALSE;
419
420         req = g_queue_pop_head (self->priv->request_queue);
421         if (!req) {
422             DBG ("request queue is empty");
423             goto _finished;
424         }
425         dbus_req = req->dbus_request;
426         if (!_is_request_supported (self, dbus_req->type)) {
427             WARN ("Request not supported -- req-type %d flags %d",
428                     dbus_req->type, self->priv->enable_flags);
429             err = TLM_GET_ERROR_FOR_ID (TLM_ERROR_DBUS_REQ_NOT_SUPPORTED,
430                     "Dbus request not supported");
431             goto _finished;
432         }
433
434         seat = self->priv->seat;
435         if (!seat && self->priv->manager) {
436             seat = tlm_manager_get_seat (self->priv->manager,
437                     dbus_req->seat_id);
438             req->seat = seat;
439             /* NOTE: When no seat is set at dbus object creation time,
440              * seat is connected on per dbus request basis and then
441              * disconnected when the dbus request is completed or aborted */
442             if (seat) {
443                 _connect_seat (self, seat);
444                 g_object_weak_ref (G_OBJECT (seat),
445                         (GWeakNotify)_on_seat_dispose, self);
446             }
447         }
448
449         if (!seat) {
450             WARN ("Cannot find the seat");
451             err = TLM_GET_ERROR_FOR_ID (TLM_ERROR_SEAT_NOT_FOUND,
452                     "Seat not found");
453             goto _finished;
454         }
455
456         self->priv->active_request = req;
457         switch(dbus_req->type) {
458         case TLM_DBUS_REQUEST_TYPE_LOGIN_USER:
459             ret = tlm_seat_create_session (seat, NULL, dbus_req->username,
460                     dbus_req->password, dbus_req->environment);
461             break;
462         case TLM_DBUS_REQUEST_TYPE_LOGOUT_USER:
463             ret = tlm_seat_terminate_session (seat);
464             break;
465         case TLM_DBUS_REQUEST_TYPE_SWITCH_USER:
466             ret = tlm_seat_switch_user (seat, NULL, dbus_req->username,
467                     dbus_req->password, dbus_req->environment);
468             break;
469         }
470         if (!ret) {
471             _dispose_request (self, self->priv->active_request);
472             self->priv->active_request = NULL;
473         }
474     }
475
476 _finished:
477     if (err) {
478         if (req) {
479             _complete_request (self, req, err);
480         } else {
481             g_error_free (err);
482         }
483     }
484     if (!self->priv->active_request)
485         _process_next_request_in_idle (self);
486
487     return FALSE;
488 }
489
490 static void
491 _process_next_request_in_idle (
492         TlmDbusObserver *self)
493 {
494     if (!self->priv->request_id &&
495         !g_queue_is_empty (self->priv->request_queue)) {
496         DBG ("request queue has request(s) to be processed");
497         self->priv->request_id = g_idle_add ((GSourceFunc)_process_request,
498                 self);
499     }
500 }
501
502 static void
503 _add_request (
504         TlmDbusObserver *self,
505         TlmRequest *request)
506 {
507     g_queue_push_tail (self->priv->request_queue, request);
508     _process_next_request_in_idle (self);
509 }
510
511 static void
512 _handle_seat_session_created (
513         TlmDbusObserver *self,
514         const gchar *seat_id,
515         GObject *seat)
516 {
517     DBG ("self %p seat %p", self, seat);
518
519     g_return_if_fail (self && TLM_IS_DBUS_OBSERVER(self));
520     g_return_if_fail (seat && TLM_IS_SEAT(seat));
521
522     /* Login/switch request should only be completed on session created
523      * signal from seat */
524     if (!self->priv->active_request ||
525         !self->priv->active_request->dbus_request ||
526         self->priv->active_request->dbus_request->type ==
527                 TLM_DBUS_REQUEST_TYPE_LOGOUT_USER)
528         return;
529
530     _complete_request (self, self->priv->active_request, NULL);
531     self->priv->active_request = NULL;
532
533     _process_next_request_in_idle (self);
534 }
535
536 static gboolean
537 _handle_seat_session_terminated (
538         TlmDbusObserver *self,
539         const gchar *seat_id,
540         GObject *seat)
541 {
542     DBG ("self %p seat %p", self, seat);
543
544     g_return_val_if_fail (self && TLM_IS_DBUS_OBSERVER(self), FALSE);
545     g_return_val_if_fail (seat && TLM_IS_SEAT(seat), FALSE);
546
547     /* Logout request should only be completed on session terminated signal
548      * from seat */
549     if (!self->priv->active_request ||
550         !self->priv->active_request->dbus_request ||
551         self->priv->active_request->dbus_request->type !=
552                 TLM_DBUS_REQUEST_TYPE_LOGOUT_USER)
553         return FALSE;
554
555     _disconnect_dbus_adapter (self, TLM_DBUS_LOGIN_ADAPTER (
556             self->priv->active_request->dbus_request->dbus_adapter));
557
558     _complete_request (self, self->priv->active_request, NULL);
559     self->priv->active_request = NULL;
560
561     _process_next_request_in_idle (self);
562
563     return FALSE;
564 }
565
566 static void
567 _handle_seat_session_error (
568         TlmDbusObserver *self,
569         TlmError error_code,
570         GObject *seat)
571 {
572     DBG ("self %p seat %p", self, seat);
573     GError *error = NULL;
574
575     g_return_if_fail (self && TLM_IS_DBUS_OBSERVER(self));
576     g_return_if_fail (seat && TLM_IS_SEAT(seat));
577
578     if (!self->priv->active_request)
579         return;
580
581     error = TLM_GET_ERROR_FOR_ID (error_code, "Dbus request failed");
582     _complete_request (self, self->priv->active_request, error);
583     self->priv->active_request = NULL;
584
585     _process_next_request_in_idle (self);
586 }
587
588 static void
589 _handle_dbus_login_user (
590         TlmDbusObserver *self,
591         const gchar *seat_id,
592         const gchar *username,
593         const gchar *password,
594         GVariant *environment,
595         GDBusMethodInvocation *invocation,
596         GObject *dbus_adapter)
597 {
598     TlmDbusRequest *request = NULL;
599
600     DBG ("seat id %s, username %s", seat_id, username);
601     g_return_if_fail (self && TLM_IS_DBUS_OBSERVER(self));
602
603     request = tlm_dbus_utils_create_request (dbus_adapter, invocation,
604             TLM_DBUS_REQUEST_TYPE_LOGIN_USER, seat_id, username, password,
605             environment);
606     _add_request (self, _create_request (self, request, NULL));
607 }
608
609 static void
610 _handle_dbus_logout_user (
611         TlmDbusObserver *self,
612         const gchar *seat_id,
613         GDBusMethodInvocation *invocation,
614         GObject *dbus_adapter)
615 {
616     TlmDbusRequest *request = NULL;
617
618     DBG ("seat id %s", seat_id);
619     g_return_if_fail (self && TLM_IS_DBUS_OBSERVER(self));
620
621     request = tlm_dbus_utils_create_request (dbus_adapter, invocation,
622             TLM_DBUS_REQUEST_TYPE_LOGOUT_USER, seat_id, NULL, NULL, NULL);
623     _add_request (self, _create_request (self, request, NULL));
624 }
625
626 static void
627 _handle_dbus_switch_user (
628         TlmDbusObserver *self,
629         const gchar *seat_id,
630         const gchar *username,
631         const gchar *password,
632         GVariant *environment,
633         GDBusMethodInvocation *invocation,
634         GObject *dbus_adapter)
635 {
636     TlmDbusRequest *request = NULL;
637
638     DBG ("seat id %s, username %s", seat_id, username);
639     g_return_if_fail (self && TLM_IS_DBUS_OBSERVER(self));
640
641     request = tlm_dbus_utils_create_request (dbus_adapter, invocation,
642             TLM_DBUS_REQUEST_TYPE_SWITCH_USER, seat_id, username, password,
643             environment);
644     _add_request (self, _create_request (self, request, NULL));
645 }
646
647 static void
648 _stop_dbus_server (TlmDbusObserver *self)
649 {
650     DBG("self %p", self);
651     _clear_request (self->priv->active_request, self);
652     self->priv->active_request = NULL;
653
654     if (self->priv->request_queue) {
655         g_queue_foreach (self->priv->request_queue,
656                            (GFunc) _clear_request, self);
657         g_queue_free (self->priv->request_queue);
658         self->priv->request_queue = NULL;
659     }
660
661     if (self->priv->dbus_server) {
662         tlm_dbus_server_stop (self->priv->dbus_server);
663         g_object_unref (self->priv->dbus_server);
664         self->priv->dbus_server = NULL;
665     }
666 }
667
668 static gboolean
669 _start_dbus_server (
670         TlmDbusObserver *self,
671         const gchar *address,
672         uid_t uid)
673 {
674     DBG("self %p address %s uid %d", self, address, uid);
675     self->priv->dbus_server = TLM_DBUS_SERVER (tlm_dbus_server_p2p_new (address,
676             uid));
677     return tlm_dbus_server_start (self->priv->dbus_server);
678 }
679
680 static void
681 tlm_dbus_observer_dispose (GObject *object)
682 {
683     TlmDbusObserver *self = TLM_DBUS_OBSERVER(object);
684     DBG("disposing dbus_observer: %p", self);
685
686     if (self->priv->request_id) {
687         g_source_remove (self->priv->request_id);
688         self->priv->request_id = 0;
689     }
690
691     _stop_dbus_server (self);
692     if (self->priv->manager) {
693         g_object_weak_unref (G_OBJECT (self->priv->manager),
694                 (GWeakNotify)_on_manager_dispose, self);
695         self->priv->manager = NULL;
696     }
697
698     if (self->priv->seat) {
699         g_object_weak_unref (G_OBJECT (self->priv->seat),
700                 (GWeakNotify)_on_seat_dispose, self);
701         self->priv->seat = NULL;
702     }
703     DBG("disposing dbus_observer DONE: %p", self);
704
705     G_OBJECT_CLASS (tlm_dbus_observer_parent_class)->dispose (object);
706 }
707
708 static void
709 tlm_dbus_observer_finalize (GObject *self)
710 {
711     //TlmDbusObserver *dbus_observer = TLM_DBUS_OBSERVER(self);
712
713     G_OBJECT_CLASS (tlm_dbus_observer_parent_class)->finalize (self);
714 }
715
716 static void
717 tlm_dbus_observer_class_init (TlmDbusObserverClass *klass)
718 {
719     GObjectClass *g_klass = G_OBJECT_CLASS (klass);
720
721     g_type_class_add_private (klass, sizeof (TlmDbusObserverPrivate));
722
723     g_klass->dispose = tlm_dbus_observer_dispose ;
724     g_klass->finalize = tlm_dbus_observer_finalize;
725 }
726
727 static void
728 tlm_dbus_observer_init (TlmDbusObserver *dbus_observer)
729 {
730     TlmDbusObserverPrivate *priv = TLM_DBUS_OBSERVER_PRIV (dbus_observer);
731     
732     priv->manager = NULL;
733     priv->seat = NULL;
734     priv->enable_flags = DBUS_OBSERVER_ENABLE_ALL;
735     priv->request_queue = g_queue_new ();
736     priv->request_id = 0;
737     priv->active_request = NULL;
738     dbus_observer->priv = priv;
739 }
740
741 TlmDbusObserver *
742 tlm_dbus_observer_new (
743         TlmManager *manager,
744         TlmSeat *seat,
745         const gchar *address,
746         uid_t uid,
747         DbusObserverEnableFlags enable_flags)
748 {
749     TlmDbusObserver *dbus_observer =
750         g_object_new (TLM_TYPE_DBUS_OBSERVER,  NULL);
751     DBG ("%p", dbus_observer);
752
753     if (manager) {
754         dbus_observer->priv->manager = manager;
755         g_object_weak_ref (G_OBJECT (manager), (GWeakNotify)_on_manager_dispose,
756                 dbus_observer);
757     }
758     /* NOTE: When no seat is set at dbus object creation time,
759      * seat is connected on per dbus request basis and then
760      * disconnected when the dbus request is completed or aborted */
761     if (seat) {
762         dbus_observer->priv->seat = seat;
763         g_object_weak_ref (G_OBJECT (seat), (GWeakNotify)_on_seat_dispose,
764                 dbus_observer);
765     }
766     dbus_observer->priv->enable_flags = enable_flags;
767
768     if (!_start_dbus_server (dbus_observer, address, uid)) {
769         WARN ("DbusObserver startup failed");
770         g_object_unref (dbus_observer);
771         return NULL;
772     }
773
774     g_signal_connect_swapped (dbus_observer->priv->dbus_server,
775             "client-added", G_CALLBACK (_handle_dbus_client_added),
776             dbus_observer);
777     g_signal_connect_swapped (dbus_observer->priv->dbus_server,
778             "client-removed", G_CALLBACK(_handle_dbus_client_removed),
779             dbus_observer);
780     return dbus_observer;
781 }