source: proiecte/PPPP/gdm/gui/simple-chooser/gdm-host-chooser-widget.c @ 134

Last change on this file since 134 was 134, checked in by (none), 14 years ago

gdm sources with the modifications for webcam

File size: 29.2 KB
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 1998, 1999, 2000 Martin K, Petersen <mkp@mkp.net>
4 * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 */
21
22#include "config.h"
23
24#include <stdlib.h>
25#include <stdio.h>
26#include <unistd.h>
27#include <string.h>
28#include <errno.h>
29#include <sys/types.h>
30#include <netinet/in.h>
31#include <sys/socket.h>
32#include <sys/ioctl.h>
33#include <net/if.h>
34#ifdef HAVE_SYS_SOCKIO_H
35#include <sys/sockio.h>
36#endif
37
38#include <X11/Xmd.h>
39#include <X11/Xdmcp.h>
40
41#include <glib.h>
42#include <glib/gi18n.h>
43#include <glib-object.h>
44#include <gtk/gtk.h>
45
46#include "gdm-address.h"
47#include "gdm-chooser-host.h"
48#include "gdm-host-chooser-widget.h"
49
50#define GDM_HOST_CHOOSER_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_HOST_CHOOSER_WIDGET, GdmHostChooserWidgetPrivate))
51
52struct GdmHostChooserWidgetPrivate
53{
54        GtkWidget      *treeview;
55
56        int             kind_mask;
57
58        char          **hosts;
59
60        XdmcpBuffer     broadcast_buf;
61        XdmcpBuffer     query_buf;
62        gboolean        have_ipv6;
63        int             socket_fd;
64        guint           io_watch_id;
65        guint           scan_time_id;
66        guint           ping_try_id;
67
68        int             ping_tries;
69
70        GSList         *broadcast_addresses;
71        GSList         *query_addresses;
72        GSList         *chooser_hosts;
73
74        GdmChooserHost *current_host;
75};
76
77enum {
78        PROP_0,
79        PROP_KIND_MASK,
80};
81
82enum {
83        HOST_ACTIVATED,
84        LAST_SIGNAL
85};
86
87static guint signals [LAST_SIGNAL] = { 0, };
88
89static void     gdm_host_chooser_widget_class_init  (GdmHostChooserWidgetClass *klass);
90static void     gdm_host_chooser_widget_init        (GdmHostChooserWidget      *host_chooser_widget);
91static void     gdm_host_chooser_widget_finalize    (GObject                   *object);
92
93G_DEFINE_TYPE (GdmHostChooserWidget, gdm_host_chooser_widget, GTK_TYPE_VBOX)
94
95#define GDM_XDMCP_PROTOCOL_VERSION 1001
96#define SCAN_TIMEOUT 30
97#define PING_TIMEOUT 2
98#define PING_TRIES 3
99
100enum {
101        CHOOSER_LIST_ICON_COLUMN = 0,
102        CHOOSER_LIST_LABEL_COLUMN,
103        CHOOSER_LIST_HOST_COLUMN
104};
105
106static void
107chooser_host_add (GdmHostChooserWidget *widget,
108                  GdmChooserHost       *host)
109{
110        widget->priv->chooser_hosts = g_slist_prepend (widget->priv->chooser_hosts, host);
111}
112
113#if 0
114static void
115chooser_host_remove (GdmHostChooserWidget *widget,
116                     GdmChooserHost       *host)
117{
118        widget->priv->chooser_hosts = g_slist_remove (widget->priv->chooser_hosts, host);
119}
120#endif
121
122static GdmChooserHost *
123find_known_host (GdmHostChooserWidget *widget,
124                 GdmAddress           *address)
125{
126        GSList         *li;
127        GdmChooserHost *host;
128
129        for (li = widget->priv->chooser_hosts; li != NULL; li = li->next) {
130                host = li->data;
131                if (gdm_address_equal (gdm_chooser_host_get_address (host), address)) {
132                        goto out;
133                }
134        }
135
136        host = NULL;
137 out:
138
139        return host;
140}
141
142static void
143browser_add_host (GdmHostChooserWidget *widget,
144                  GdmChooserHost       *host)
145{
146        char         *hostname;
147        char         *name;
148        char         *desc;
149        char         *label;
150        GtkTreeModel *model;
151        GtkTreeIter   iter;
152        gboolean      res;
153
154        g_assert (host != NULL);
155
156        if (! gdm_chooser_host_get_willing (host)) {
157                gtk_widget_set_sensitive (GTK_WIDGET (widget), TRUE);
158                return;
159        }
160
161        res = gdm_address_get_hostname (gdm_chooser_host_get_address (host), &hostname);
162        if (! res) {
163                gdm_address_get_numeric_info (gdm_chooser_host_get_address (host), &hostname, NULL);
164        }
165
166        name = g_markup_escape_text (hostname, -1);
167        desc = g_markup_escape_text (gdm_chooser_host_get_description (host), -1);
168        label = g_strdup_printf ("<b>%s</b>\n%s", name, desc);
169        g_free (name);
170        g_free (desc);
171
172        model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget->priv->treeview));
173
174        gtk_list_store_append (GTK_LIST_STORE (model), &iter);
175        gtk_list_store_set (GTK_LIST_STORE (model),
176                            &iter,
177                            CHOOSER_LIST_ICON_COLUMN, NULL,
178                            CHOOSER_LIST_LABEL_COLUMN, label,
179                            CHOOSER_LIST_HOST_COLUMN, host,
180                            -1);
181        g_free (label);
182
183}
184
185static gboolean
186decode_packet (GIOChannel           *source,
187               GIOCondition          condition,
188               GdmHostChooserWidget *widget)
189{
190        struct sockaddr_storage clnt_ss;
191        GdmAddress             *address;
192        int                     ss_len;
193        XdmcpHeader             header;
194        int                     res;
195        static XdmcpBuffer      buf;
196        ARRAY8                  auth = {0};
197        ARRAY8                  host = {0};
198        ARRAY8                  stat = {0};
199        char                   *status;
200        GdmChooserHost         *chooser_host;
201
202        status = NULL;
203        address = NULL;
204
205        g_debug ("decode_packet: GIOCondition %d", (int)condition);
206
207        if ( ! (condition & G_IO_IN)) {
208                return TRUE;
209        }
210
211        ss_len = sizeof (clnt_ss);
212        res = XdmcpFill (widget->priv->socket_fd, &buf, (XdmcpNetaddr)&clnt_ss, &ss_len);
213        if G_UNLIKELY (! res) {
214                g_debug (_("XDMCP: Could not create XDMCP buffer!"));
215                return TRUE;
216        }
217
218        res = XdmcpReadHeader (&buf, &header);
219        if G_UNLIKELY (! res) {
220                g_warning (_("XDMCP: Could not read XDMCP header!"));
221                return TRUE;
222        }
223
224        if G_UNLIKELY (header.version != XDM_PROTOCOL_VERSION &&
225                       header.version != GDM_XDMCP_PROTOCOL_VERSION) {
226                g_warning (_("XMDCP: Incorrect XDMCP version!"));
227                return TRUE;
228        }
229
230        address = gdm_address_new_from_sockaddr ((struct sockaddr *) &clnt_ss, ss_len);
231        if (address == NULL) {
232                g_warning (_("XMDCP: Unable to parse address"));
233                return TRUE;
234        }
235
236        gdm_address_debug (address);
237
238        if (header.opcode == WILLING) {
239                if (! XdmcpReadARRAY8 (&buf, &auth)) {
240                        goto done;
241                }
242
243                if (! XdmcpReadARRAY8 (&buf, &host)) {
244                        goto done;
245                }
246
247                if (! XdmcpReadARRAY8 (&buf, &stat)) {
248                        goto done;
249                }
250
251                status = g_strndup ((char *) stat.data, MIN (stat.length, 256));
252        } else if (header.opcode == UNWILLING) {
253                /* immaterial, will not be shown */
254                status = NULL;
255        } else {
256                goto done;
257        }
258
259        g_debug ("STATUS: %s", status);
260
261        chooser_host = find_known_host (widget, address);
262        if (chooser_host == NULL) {
263                chooser_host = g_object_new (GDM_TYPE_CHOOSER_HOST,
264                                             "address", address,
265                                             "description", status,
266                                             "willing", (header.opcode == WILLING),
267                                             "kind", GDM_CHOOSER_HOST_KIND_XDMCP,
268                                             NULL);
269                chooser_host_add (widget, chooser_host);
270                browser_add_host (widget, chooser_host);
271        } else {
272                /* server changed it's mind */
273                if (header.opcode == WILLING
274                    && ! gdm_chooser_host_get_willing (chooser_host)) {
275                        g_object_set (chooser_host, "willing", TRUE, NULL);
276                        browser_add_host (widget, chooser_host);
277                }
278                /* FIXME: handle unwilling? */
279        }
280
281 done:
282        if (header.opcode == WILLING) {
283                XdmcpDisposeARRAY8 (&auth);
284                XdmcpDisposeARRAY8 (&host);
285                XdmcpDisposeARRAY8 (&stat);
286        }
287
288        g_free (status);
289        gdm_address_free (address);
290
291        return TRUE;
292}
293
294static void
295do_ping (GdmHostChooserWidget *widget,
296         gboolean              full)
297{
298        GSList *l;
299
300        g_debug ("do ping full:%d", full);
301
302        for (l = widget->priv->broadcast_addresses; l != NULL; l = l->next) {
303                GdmAddress              *address;
304                int                      res;
305
306                address = l->data;
307
308                gdm_address_debug (address);
309                errno = 0;
310                g_debug ("fd:%d", widget->priv->socket_fd);
311                res = XdmcpFlush (widget->priv->socket_fd,
312                                  &widget->priv->broadcast_buf,
313                                  (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
314                                  (int)sizeof (struct sockaddr_storage));
315                if (! res) {
316                        g_warning ("Unable to flush the XDMCP broadcast packet: %s", g_strerror (errno));
317                }
318        }
319
320        if (full) {
321                for (l = widget->priv->query_addresses; l != NULL; l = l->next) {
322                        GdmAddress *address;
323                        int         res;
324
325                        address = l->data;
326
327                        gdm_address_debug (address);
328                        res = XdmcpFlush (widget->priv->socket_fd,
329                                          &widget->priv->query_buf,
330                                          (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
331                                          (int)sizeof (struct sockaddr_storage));
332                        if (! res) {
333                                g_warning ("Unable to flush the XDMCP query packet");
334                        }
335                }
336        }
337}
338
339static gboolean
340ping_try (GdmHostChooserWidget *widget)
341{
342        do_ping (widget, FALSE);
343
344        widget->priv->ping_tries --;
345
346        if (widget->priv->ping_tries <= 0) {
347                widget->priv->ping_try_id = 0;
348                return FALSE;
349        } else {
350                return TRUE;
351        }
352}
353
354static void
355xdmcp_discover (GdmHostChooserWidget *widget)
356{
357#if 0
358        gtk_widget_set_sensitive (GTK_WIDGET (manage), FALSE);
359        gtk_widget_set_sensitive (GTK_WIDGET (rescan), FALSE);
360        gtk_list_store_clear (GTK_LIST_STORE (browser_model));
361        gtk_widget_set_sensitive (GTK_WIDGET (browser), FALSE);
362        gtk_label_set_label (GTK_LABEL (status_label),
363                             _(scanning_message));
364
365        while (hl) {
366                gdm_chooser_host_dispose ((GdmChooserHost *) hl->data);
367                hl = hl->next;
368        }
369
370        g_list_free (chooser_hosts);
371        chooser_hosts = NULL;
372#endif
373
374        do_ping (widget, TRUE);
375
376#if 0
377        if (widget->priv->scan_time_id > 0) {
378                g_source_remove (widget->priv->scan_time_id);
379        }
380
381        widget->priv->scan_time_id = g_timeout_add_seconds (SCAN_TIMEOUT,
382                                                            chooser_scan_time_update,
383                                                            widget);
384#endif
385        /* Note we already used up one try */
386        widget->priv->ping_tries = PING_TRIES - 1;
387        if (widget->priv->ping_try_id > 0) {
388                g_source_remove (widget->priv->ping_try_id);
389        }
390
391        widget->priv->ping_try_id = g_timeout_add_seconds (PING_TIMEOUT,
392                                                           (GSourceFunc)ping_try,
393                                                           widget);
394}
395
396/* Find broadcast address for all active, non pointopoint interfaces */
397static void
398find_broadcast_addresses (GdmHostChooserWidget *widget)
399{
400        int           i;
401        int           num;
402        int           sock;
403        struct ifconf ifc;
404        char         *buf;
405        struct ifreq *ifr;
406
407        g_debug ("Finding broadcast addresses");
408
409        sock = socket (AF_INET, SOCK_DGRAM, 0);
410#ifdef SIOCGIFNUM
411        if (ioctl (sock, SIOCGIFNUM, &num) < 0) {
412                num = 64;
413        }
414#else
415        num = 64;
416#endif
417
418        ifc.ifc_len = sizeof (struct ifreq) * num;
419        ifc.ifc_buf = buf = g_malloc0 (ifc.ifc_len);
420        if (ioctl (sock, SIOCGIFCONF, &ifc) < 0) {
421                g_warning ("Could not get local addresses!");
422                goto out;
423        }
424
425        ifr = ifc.ifc_req;
426        num = ifc.ifc_len / sizeof (struct ifreq);
427        for (i = 0 ; i < num ; i++) {
428                const char *name;
429
430                name = ifr[i].ifr_name;
431                g_debug ("Checking if %s", name);
432                if (name != NULL && name[0] != '\0') {
433                        struct ifreq            ifreq;
434                        GdmAddress             *address;
435                        struct sockaddr_in      sin;
436
437                        memset (&ifreq, 0, sizeof (ifreq));
438
439                        strncpy (ifreq.ifr_name,
440                                 ifr[i].ifr_name,
441                                 sizeof (ifreq.ifr_name));
442                        /* paranoia */
443                        ifreq.ifr_name[sizeof (ifreq.ifr_name) - 1] = '\0';
444
445                        if (ioctl (sock, SIOCGIFFLAGS, &ifreq) < 0) {
446                                g_warning ("Could not get SIOCGIFFLAGS for %s", ifr[i].ifr_name);
447                        }
448
449                        if ((ifreq.ifr_flags & IFF_UP) == 0 ||
450                            (ifreq.ifr_flags & IFF_BROADCAST) == 0 ||
451                            ioctl (sock, SIOCGIFBRDADDR, &ifreq) < 0) {
452                                g_debug ("Skipping if %s", name);
453                                continue;
454                        }
455
456                        g_memmove (&sin, &ifreq.ifr_broadaddr, sizeof (struct sockaddr_in));
457                        sin.sin_port = htons (XDM_UDP_PORT);
458                        address = gdm_address_new_from_sockaddr ((struct sockaddr *) &sin, sizeof (sin));
459                        if (address != NULL) {
460                                g_debug ("Adding if %s", name);
461                                gdm_address_debug (address);
462
463                                widget->priv->broadcast_addresses = g_slist_append (widget->priv->broadcast_addresses, address);
464                        }
465                }
466        }
467 out:
468        g_free (buf);
469        close (sock);
470}
471
472static void
473add_hosts (GdmHostChooserWidget *widget)
474{
475        int i;
476
477        for (i = 0; widget->priv->hosts != NULL && widget->priv->hosts[i] != NULL; i++) {
478                struct addrinfo  hints;
479                struct addrinfo *result;
480                struct addrinfo *ai;
481                int              gaierr;
482                const char      *name;
483                char             serv_buf [NI_MAXSERV];
484                const char      *serv;
485
486                name = widget->priv->hosts[i];
487
488                if (strcmp (name, "BROADCAST") == 0) {
489                        find_broadcast_addresses (widget);
490                        continue;
491                }
492
493                if (strcmp (name, "MULTICAST") == 0) {
494                        /*gdm_chooser_find_mcaddr ();*/
495                        continue;
496                }
497
498                result = NULL;
499                memset (&hints, 0, sizeof (hints));
500                hints.ai_socktype = SOCK_STREAM;
501
502                snprintf (serv_buf, sizeof (serv_buf), "%u", XDM_UDP_PORT);
503                serv = serv_buf;
504
505                gaierr = getaddrinfo (name, serv, &hints, &result);
506                if (gaierr != 0) {
507                        g_warning ("Unable to get address info for name %s: %s", name, gai_strerror (gaierr));
508                        continue;
509                }
510
511                for (ai = result; ai != NULL; ai = ai->ai_next) {
512                        GdmAddress *address;
513
514                        address = gdm_address_new_from_sockaddr (ai->ai_addr, ai->ai_addrlen);
515                        if (address != NULL) {
516                                widget->priv->query_addresses = g_slist_append (widget->priv->query_addresses, address);
517                        }
518                }
519
520                freeaddrinfo (result);
521        }
522
523        if (widget->priv->broadcast_addresses == NULL && widget->priv->query_addresses == NULL) {
524                find_broadcast_addresses (widget);
525        }
526}
527
528static void
529xdmcp_init (GdmHostChooserWidget *widget)
530{
531        XdmcpHeader   header;
532        int           sockopts;
533        int           res;
534        GIOChannel   *ioc;
535        ARRAYofARRAY8 aanames;
536
537        sockopts = 1;
538
539        widget->priv->socket_fd = -1;
540
541        /* Open socket for communication */
542#ifdef ENABLE_IPV6
543        widget->priv->socket_fd = socket (AF_INET6, SOCK_DGRAM, 0);
544        if (widget->priv->socket_fd != -1) {
545                widget->priv->have_ipv6 = TRUE;
546        }
547#endif
548        if (! widget->priv->have_ipv6) {
549                widget->priv->socket_fd = socket (AF_INET, SOCK_DGRAM, 0);
550                if (widget->priv->socket_fd == -1) {
551                        g_critical ("Could not create socket!");
552                }
553        }
554
555        res = setsockopt (widget->priv->socket_fd,
556                          SOL_SOCKET,
557                          SO_BROADCAST,
558                          (char *) &sockopts,
559                          sizeof (sockopts));
560        if (res < 0) {
561                g_critical ("Could not set socket options!");
562        }
563
564        /* Assemble XDMCP BROADCAST_QUERY packet in static buffer */
565        memset (&header, 0, sizeof (XdmcpHeader));
566        header.opcode  = (CARD16) BROADCAST_QUERY;
567        header.length  = 1;
568        header.version = XDM_PROTOCOL_VERSION;
569        aanames.length = 0;
570        XdmcpWriteHeader (&widget->priv->broadcast_buf, &header);
571        XdmcpWriteARRAYofARRAY8 (&widget->priv->broadcast_buf, &aanames);
572
573        /* Assemble XDMCP QUERY packet in static buffer */
574        memset (&header, 0, sizeof (XdmcpHeader));
575        header.opcode  = (CARD16) QUERY;
576        header.length  = 1;
577        header.version = XDM_PROTOCOL_VERSION;
578        memset (&widget->priv->query_buf, 0, sizeof (XdmcpBuffer));
579        XdmcpWriteHeader (&widget->priv->query_buf, &header);
580        XdmcpWriteARRAYofARRAY8 (&widget->priv->query_buf, &aanames);
581
582        add_hosts (widget);
583
584        ioc = g_io_channel_unix_new (widget->priv->socket_fd);
585        g_io_channel_set_encoding (ioc, NULL, NULL);
586        g_io_channel_set_buffered (ioc, FALSE);
587        widget->priv->io_watch_id = g_io_add_watch (ioc,
588                                                    G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
589                                                    (GIOFunc)decode_packet,
590                                                    widget);
591        g_io_channel_unref (ioc);
592}
593
594void
595gdm_host_chooser_widget_refresh (GdmHostChooserWidget *widget)
596{
597        g_return_if_fail (GDM_IS_HOST_CHOOSER_WIDGET (widget));
598
599        xdmcp_discover (widget);
600}
601
602GdmChooserHost *
603gdm_host_chooser_widget_get_host (GdmHostChooserWidget *widget)
604{
605        GdmChooserHost *host;
606
607        g_return_val_if_fail (GDM_IS_HOST_CHOOSER_WIDGET (widget), NULL);
608
609        host = NULL;
610        if (widget->priv->current_host != NULL) {
611                host = g_object_ref (widget->priv->current_host);
612        }
613
614        return host;
615}
616
617static void
618_gdm_host_chooser_widget_set_kind_mask (GdmHostChooserWidget *widget,
619                                        int                   kind_mask)
620{
621        if (widget->priv->kind_mask != kind_mask) {
622                widget->priv->kind_mask = kind_mask;
623        }
624}
625
626static void
627gdm_host_chooser_widget_set_property (GObject        *object,
628                                      guint           prop_id,
629                                      const GValue   *value,
630                                      GParamSpec     *pspec)
631{
632        GdmHostChooserWidget *self;
633
634        self = GDM_HOST_CHOOSER_WIDGET (object);
635
636        switch (prop_id) {
637        case PROP_KIND_MASK:
638                _gdm_host_chooser_widget_set_kind_mask (self, g_value_get_int (value));
639                break;
640        default:
641                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
642                break;
643        }
644}
645
646static void
647gdm_host_chooser_widget_get_property (GObject        *object,
648                                      guint           prop_id,
649                                      GValue         *value,
650                                      GParamSpec     *pspec)
651{
652        switch (prop_id) {
653        default:
654                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
655                break;
656        }
657}
658
659static GObject *
660gdm_host_chooser_widget_constructor (GType                  type,
661                                     guint                  n_construct_properties,
662                                     GObjectConstructParam *construct_properties)
663{
664        GdmHostChooserWidget      *widget;
665
666        widget = GDM_HOST_CHOOSER_WIDGET (G_OBJECT_CLASS (gdm_host_chooser_widget_parent_class)->constructor (type,
667                                                                                                                           n_construct_properties,
668                                                                                                                           construct_properties));
669
670        xdmcp_init (widget);
671        xdmcp_discover (widget);
672
673        return G_OBJECT (widget);
674}
675
676static void
677gdm_host_chooser_widget_dispose (GObject *object)
678{
679        GdmHostChooserWidget *widget;
680
681        widget = GDM_HOST_CHOOSER_WIDGET (object);
682
683        g_debug ("Disposing host_chooser_widget");
684
685        if (widget->priv->broadcast_addresses != NULL) {
686                g_slist_foreach (widget->priv->broadcast_addresses,
687                                 (GFunc)gdm_address_free,
688                                 NULL);
689                g_slist_free (widget->priv->broadcast_addresses);
690                widget->priv->broadcast_addresses = NULL;
691        }
692        if (widget->priv->query_addresses != NULL) {
693                g_slist_foreach (widget->priv->query_addresses,
694                                 (GFunc)gdm_address_free,
695                                 NULL);
696                g_slist_free (widget->priv->query_addresses);
697                widget->priv->query_addresses = NULL;
698        }
699        if (widget->priv->chooser_hosts != NULL) {
700                g_slist_foreach (widget->priv->chooser_hosts,
701                                 (GFunc)g_object_unref,
702                                 NULL);
703                g_slist_free (widget->priv->chooser_hosts);
704                widget->priv->chooser_hosts = NULL;
705        }
706
707        widget->priv->current_host = NULL;
708
709        G_OBJECT_CLASS (gdm_host_chooser_widget_parent_class)->dispose (object);
710}
711
712static void
713gdm_host_chooser_widget_class_init (GdmHostChooserWidgetClass *klass)
714{
715        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
716
717        object_class->get_property = gdm_host_chooser_widget_get_property;
718        object_class->set_property = gdm_host_chooser_widget_set_property;
719        object_class->constructor = gdm_host_chooser_widget_constructor;
720        object_class->dispose = gdm_host_chooser_widget_dispose;
721        object_class->finalize = gdm_host_chooser_widget_finalize;
722
723        g_object_class_install_property (object_class,
724                                         PROP_KIND_MASK,
725                                         g_param_spec_int ("kind-mask",
726                                                           "kind mask",
727                                                           "kind mask",
728                                                           0,
729                                                           G_MAXINT,
730                                                           0,
731                                                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
732
733        signals [HOST_ACTIVATED] = g_signal_new ("host-activated",
734                                                 G_TYPE_FROM_CLASS (object_class),
735                                                 G_SIGNAL_RUN_LAST,
736                                                 G_STRUCT_OFFSET (GdmHostChooserWidgetClass, host_activated),
737                                                 NULL,
738                                                 NULL,
739                                                 g_cclosure_marshal_VOID__VOID,
740                                                 G_TYPE_NONE,
741                                                 0);
742
743        g_type_class_add_private (klass, sizeof (GdmHostChooserWidgetPrivate));
744}
745
746static void
747on_host_selected (GtkTreeSelection     *selection,
748                  GdmHostChooserWidget *widget)
749{
750        GtkTreeModel   *model = NULL;
751        GtkTreeIter     iter = {0};
752        GdmChooserHost *curhost;
753
754        curhost = NULL;
755
756        if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
757                gtk_tree_model_get (model, &iter, CHOOSER_LIST_HOST_COLUMN, &curhost, -1);
758        }
759
760        widget->priv->current_host = curhost;
761}
762
763static void
764on_row_activated (GtkTreeView          *tree_view,
765                  GtkTreePath          *tree_path,
766                  GtkTreeViewColumn    *tree_column,
767                  GdmHostChooserWidget *widget)
768{
769        g_signal_emit (widget, signals[HOST_ACTIVATED], 0);
770}
771
772static void
773gdm_host_chooser_widget_init (GdmHostChooserWidget *widget)
774{
775        GtkWidget         *scrolled;
776        GtkTreeSelection  *selection;
777        GtkTreeViewColumn *column;
778        GtkTreeModel      *model;
779
780        widget->priv = GDM_HOST_CHOOSER_WIDGET_GET_PRIVATE (widget);
781
782        scrolled = gtk_scrolled_window_new (NULL, NULL);
783        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
784                                             GTK_SHADOW_IN);
785        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
786                                        GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
787        gtk_box_pack_start (GTK_BOX (widget), scrolled, TRUE, TRUE, 0);
788
789        widget->priv->treeview = gtk_tree_view_new ();
790        gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (widget->priv->treeview), FALSE);
791        g_signal_connect (widget->priv->treeview,
792                          "row-activated",
793                          G_CALLBACK (on_row_activated),
794                          widget);
795        gtk_container_add (GTK_CONTAINER (scrolled), widget->priv->treeview);
796
797        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->treeview));
798        gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
799        g_signal_connect (selection, "changed",
800                          G_CALLBACK (on_host_selected),
801                          widget);
802
803        model = (GtkTreeModel *)gtk_list_store_new (3,
804                                                    GDK_TYPE_PIXBUF,
805                                                    G_TYPE_STRING,
806                                                    G_TYPE_POINTER);
807        gtk_tree_view_set_model (GTK_TREE_VIEW (widget->priv->treeview), model);
808
809        column = gtk_tree_view_column_new_with_attributes ("Icon",
810                                                           gtk_cell_renderer_pixbuf_new (),
811                                                           "pixbuf", CHOOSER_LIST_ICON_COLUMN,
812                                                           NULL);
813        gtk_tree_view_append_column (GTK_TREE_VIEW (widget->priv->treeview), column);
814
815        column = gtk_tree_view_column_new_with_attributes ("Hostname",
816                                                           gtk_cell_renderer_text_new (),
817                                                           "markup", CHOOSER_LIST_LABEL_COLUMN,
818                                                           NULL);
819        gtk_tree_view_append_column (GTK_TREE_VIEW (widget->priv->treeview), column);
820
821        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
822                                              CHOOSER_LIST_LABEL_COLUMN,
823                                              GTK_SORT_ASCENDING);
824}
825
826static void
827gdm_host_chooser_widget_finalize (GObject *object)
828{
829        GdmHostChooserWidget *host_chooser_widget;
830
831        g_return_if_fail (object != NULL);
832        g_return_if_fail (GDM_IS_HOST_CHOOSER_WIDGET (object));
833
834        host_chooser_widget = GDM_HOST_CHOOSER_WIDGET (object);
835
836        g_return_if_fail (host_chooser_widget->priv != NULL);
837
838        G_OBJECT_CLASS (gdm_host_chooser_widget_parent_class)->finalize (object);
839}
840
841GtkWidget *
842gdm_host_chooser_widget_new (int kind_mask)
843{
844        GObject *object;
845
846        object = g_object_new (GDM_TYPE_HOST_CHOOSER_WIDGET,
847                               "kind-mask", kind_mask,
848                               NULL);
849
850        return GTK_WIDGET (object);
851}
Note: See TracBrowser for help on using the repository browser.