~jordunn/meenix/Master

« back to all changes in this revision

Viewing changes to src/gtk/chanview.c

  • Committer: Jordan Dunn
  • Date: 2011-05-01 22:42:27 UTC
  • Revision ID: git-v1:1ba1788f6af88891278ff2926d536c40144bc581
MovingĀ filesĀ around

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* abstract channel view: tabs or tree or anything you like */
 
2
 
 
3
#include <stdlib.h>
 
4
#include <string.h>
 
5
 
 
6
#include <gtk/gtk.h>
 
7
 
 
8
#include "chanview.h"
 
9
#include "gtkutil.h"
 
10
 
 
11
 
 
12
/* treeStore columns */
 
13
 
 
14
#define COL_NAME 0              /* (char *) */
 
15
#define COL_CHAN 1              /* (chan *) */
 
16
#define COL_ATTR 2              /* (PangoAttrList *) */
 
17
#define COL_PIXBUF 3            /* (GdkPixbuf *) */
 
18
 
 
19
struct _chanview
 
20
{
 
21
        /* impl scratch area */
 
22
        char implscratch[sizeof (void *) * 8];
 
23
 
 
24
        GtkTreeStore *store;
 
25
        int size;                       /* number of channels in view */
 
26
 
 
27
        GtkWidget *box; /* the box we destroy when changing implementations */
 
28
        GtkStyle *style;        /* style used for tree */
 
29
        chan *focused;          /* currently focused channel */
 
30
        int trunc_len;
 
31
 
 
32
        /* callbacks */
 
33
        void (*cb_focus) (chanview *, chan *, int tag, void *userdata);
 
34
        void (*cb_xbutton) (chanview *, chan *, int tag, void *userdata);
 
35
        gboolean (*cb_contextmenu) (chanview *, chan *, int tag, void *userdata, GdkEventButton *);
 
36
        int (*cb_compare) (void *a, void *b);
 
37
 
 
38
        /* impl */
 
39
        void (*func_init) (chanview *);
 
40
        void (*func_postinit) (chanview *);
 
41
        void *(*func_add) (chanview *, chan *, char *, GtkTreeIter *);
 
42
        void (*func_move_focus) (chanview *, gboolean, int);
 
43
        void (*func_change_orientation) (chanview *);
 
44
        void (*func_remove) (chan *);
 
45
        void (*func_move) (chan *, int delta);
 
46
        void (*func_move_family) (chan *, int delta);
 
47
        void (*func_focus) (chan *);
 
48
        void (*func_set_color) (chan *, PangoAttrList *);
 
49
        void (*func_rename) (chan *, char *);
 
50
        gboolean (*func_is_collapsed) (chan *);
 
51
        chan *(*func_get_parent) (chan *);
 
52
        void (*func_cleanup) (chanview *);
 
53
 
 
54
        unsigned int sorted:1;
 
55
        unsigned int vertical:1;
 
56
        unsigned int use_icons:1;
 
57
};
 
58
 
 
59
struct _chan
 
60
{
 
61
        chanview *cv;   /* our owner */
 
62
        GtkTreeIter iter;
 
63
        void *userdata; /* session * */
 
64
        void *family;           /* server * or null */
 
65
        void *impl;     /* togglebutton or null */
 
66
        GdkPixbuf *icon;
 
67
        short allow_closure;    /* allow it to be closed when it still has children? */
 
68
        short tag;
 
69
};
 
70
 
 
71
static chan *cv_find_chan_by_number (chanview *cv, int num);
 
72
static int cv_find_number_of_chan (chanview *cv, chan *find_ch);
 
73
 
 
74
 
 
75
/* ======= TABS ======= */
 
76
 
 
77
#include "chanview-tabs.c"
 
78
 
 
79
 
 
80
/* ======= TREE ======= */
 
81
 
 
82
#include "chanview-tree.c"
 
83
 
 
84
 
 
85
/* ==== ABSTRACT CHANVIEW ==== */
 
86
 
 
87
static char *
 
88
truncate_tab_name (char *name, int max)
 
89
{
 
90
        char *buf;
 
91
 
 
92
        if (max > 2 && g_utf8_strlen (name, -1) > max)
 
93
        {
 
94
                /* truncate long channel names */
 
95
                buf = malloc (strlen (name) + 4);
 
96
                strcpy (buf, name);
 
97
                g_utf8_offset_to_pointer (buf, max)[0] = 0;
 
98
                strcat (buf, "..");
 
99
                return buf;
 
100
        }
 
101
 
 
102
        return name;
 
103
}
 
104
 
 
105
/* iterate through a model, into 1 depth of children */
 
106
 
 
107
static void
 
108
model_foreach_1 (GtkTreeModel *model, void (*func)(void *, GtkTreeIter *),
 
109
                                          void *userdata)
 
110
{
 
111
        GtkTreeIter iter, inner;
 
112
 
 
113
        if (gtk_tree_model_get_iter_first (model, &iter))
 
114
        {
 
115
                do
 
116
                {
 
117
                        func (userdata, &iter);
 
118
                        if (gtk_tree_model_iter_children (model, &inner, &iter))
 
119
                        {
 
120
                                do
 
121
                                        func (userdata, &inner);
 
122
                                while (gtk_tree_model_iter_next (model, &inner));
 
123
                        }
 
124
                }
 
125
                while (gtk_tree_model_iter_next (model, &iter));
 
126
        }
 
127
}
 
128
 
 
129
static void
 
130
chanview_pop_cb (chanview *cv, GtkTreeIter *iter)
 
131
{
 
132
        chan *ch;
 
133
        char *name;
 
134
        PangoAttrList *attr;
 
135
 
 
136
        gtk_tree_model_get (GTK_TREE_MODEL (cv->store), iter,
 
137
                                                          COL_NAME, &name, COL_CHAN, &ch, COL_ATTR, &attr, -1);
 
138
        ch->impl = cv->func_add (cv, ch, name, NULL);
 
139
        if (attr)
 
140
        {
 
141
                cv->func_set_color (ch, attr);
 
142
                pango_attr_list_unref (attr);
 
143
        }
 
144
        g_free (name);
 
145
}
 
146
 
 
147
static void
 
148
chanview_populate (chanview *cv)
 
149
{
 
150
        model_foreach_1 (GTK_TREE_MODEL (cv->store), (void *)chanview_pop_cb, cv);
 
151
}
 
152
 
 
153
void
 
154
chanview_set_impl (chanview *cv, int type)
 
155
{
 
156
        /* cleanup the old one */
 
157
        if (cv->func_cleanup)
 
158
                cv->func_cleanup (cv);
 
159
 
 
160
        switch (type)
 
161
        {
 
162
        case 0:
 
163
                cv->func_init = cv_tabs_init;
 
164
                cv->func_postinit = cv_tabs_postinit;
 
165
                cv->func_add = cv_tabs_add;
 
166
                cv->func_move_focus = cv_tabs_move_focus;
 
167
                cv->func_change_orientation = cv_tabs_change_orientation;
 
168
                cv->func_remove = cv_tabs_remove;
 
169
                cv->func_move = cv_tabs_move;
 
170
                cv->func_move_family = cv_tabs_move_family;
 
171
                cv->func_focus = cv_tabs_focus;
 
172
                cv->func_set_color = cv_tabs_set_color;
 
173
                cv->func_rename = cv_tabs_rename;
 
174
                cv->func_is_collapsed = cv_tabs_is_collapsed;
 
175
                cv->func_get_parent = cv_tabs_get_parent;
 
176
                cv->func_cleanup = cv_tabs_cleanup;
 
177
                break;
 
178
 
 
179
        default:
 
180
                cv->func_init = cv_tree_init;
 
181
                cv->func_postinit = cv_tree_postinit;
 
182
                cv->func_add = cv_tree_add;
 
183
                cv->func_move_focus = cv_tree_move_focus;
 
184
                cv->func_change_orientation = cv_tree_change_orientation;
 
185
                cv->func_remove = cv_tree_remove;
 
186
                cv->func_move = cv_tree_move;
 
187
                cv->func_move_family = cv_tree_move_family;
 
188
                cv->func_focus = cv_tree_focus;
 
189
                cv->func_set_color = cv_tree_set_color;
 
190
                cv->func_rename = cv_tree_rename;
 
191
                cv->func_is_collapsed = cv_tree_is_collapsed;
 
192
                cv->func_get_parent = cv_tree_get_parent;
 
193
                cv->func_cleanup = cv_tree_cleanup;
 
194
                break;
 
195
        }
 
196
 
 
197
        /* now rebuild a new tabbar or tree */
 
198
        cv->func_init (cv);
 
199
 
 
200
        chanview_populate (cv);
 
201
 
 
202
        cv->func_postinit (cv);
 
203
 
 
204
        /* force re-focus */
 
205
        if (cv->focused)
 
206
                cv->func_focus (cv->focused);
 
207
}
 
208
 
 
209
static void
 
210
chanview_free_ch (chanview *cv, GtkTreeIter *iter)
 
211
{
 
212
        chan *ch;
 
213
 
 
214
        gtk_tree_model_get (GTK_TREE_MODEL (cv->store), iter, COL_CHAN, &ch, -1);
 
215
        free (ch);
 
216
}
 
217
 
 
218
static void
 
219
chanview_destroy_store (chanview *cv)   /* free every (chan *) in the store */
 
220
{
 
221
        model_foreach_1 (GTK_TREE_MODEL (cv->store), (void *)chanview_free_ch, cv);
 
222
        g_object_unref (cv->store);
 
223
}
 
224
 
 
225
static void
 
226
chanview_destroy (chanview *cv)
 
227
{
 
228
        if (cv->func_cleanup)
 
229
                cv->func_cleanup (cv);
 
230
 
 
231
        if (cv->box)
 
232
                gtk_widget_destroy (cv->box);
 
233
 
 
234
        chanview_destroy_store (cv);
 
235
        free (cv);
 
236
}
 
237
 
 
238
static void
 
239
chanview_box_destroy_cb (GtkWidget *box, chanview *cv)
 
240
{
 
241
        cv->box = NULL;
 
242
        chanview_destroy (cv);
 
243
}
 
244
 
 
245
chanview *
 
246
chanview_new (int type, int trunc_len, gboolean sort, gboolean use_icons,
 
247
                                  GtkStyle *style)
 
248
{
 
249
        chanview *cv;
 
250
 
 
251
        cv = calloc (1, sizeof (chanview));
 
252
        cv->store = gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER,
 
253
                                                                                          PANGO_TYPE_ATTR_LIST, GDK_TYPE_PIXBUF);
 
254
        cv->style = style;
 
255
        cv->box = gtk_hbox_new (0, 0);
 
256
        cv->trunc_len = trunc_len;
 
257
        cv->sorted = sort;
 
258
        cv->use_icons = use_icons;
 
259
        gtk_widget_show (cv->box);
 
260
        chanview_set_impl (cv, type);
 
261
 
 
262
        g_signal_connect (G_OBJECT (cv->box), "destroy",
 
263
                                                        G_CALLBACK (chanview_box_destroy_cb), cv);
 
264
 
 
265
        return cv;
 
266
}
 
267
 
 
268
/* too lazy for signals */
 
269
 
 
270
void
 
271
chanview_set_callbacks (chanview *cv,
 
272
        void (*cb_focus) (chanview *, chan *, int tag, void *userdata),
 
273
        void (*cb_xbutton) (chanview *, chan *, int tag, void *userdata),
 
274
        gboolean (*cb_contextmenu) (chanview *, chan *, int tag, void *userdata, GdkEventButton *),
 
275
        int (*cb_compare) (void *a, void *b))
 
276
{
 
277
        cv->cb_focus = cb_focus;
 
278
        cv->cb_xbutton = cb_xbutton;
 
279
        cv->cb_contextmenu = cb_contextmenu;
 
280
        cv->cb_compare = cb_compare;
 
281
}
 
282
 
 
283
/* find a place to insert this new entry, based on the compare function */
 
284
 
 
285
static void
 
286
chanview_insert_sorted (chanview *cv, GtkTreeIter *add_iter, GtkTreeIter *parent, void *ud)
 
287
{
 
288
        GtkTreeIter iter;
 
289
        chan *ch;
 
290
 
 
291
        if (cv->sorted && gtk_tree_model_iter_children (GTK_TREE_MODEL (cv->store), &iter, parent))
 
292
        {
 
293
                do
 
294
                {
 
295
                        gtk_tree_model_get (GTK_TREE_MODEL (cv->store), &iter, COL_CHAN, &ch, -1);
 
296
                        if (ch->tag == 0 && cv->cb_compare (ch->userdata, ud) > 0)
 
297
                        {
 
298
                                gtk_tree_store_insert_before (cv->store, add_iter, parent, &iter);
 
299
                                return;
 
300
                        }
 
301
                }
 
302
                while (gtk_tree_model_iter_next (GTK_TREE_MODEL (cv->store), &iter));
 
303
        }
 
304
 
 
305
        gtk_tree_store_append (cv->store, add_iter, parent);
 
306
}
 
307
 
 
308
/* find a parent node with the same "family" pointer (i.e. the Server tab) */
 
309
 
 
310
static int
 
311
chanview_find_parent (chanview *cv, void *family, GtkTreeIter *search_iter, chan *avoid)
 
312
{
 
313
        chan *search_ch;
 
314
 
 
315
        /* find this new row's parent, if any */
 
316
        if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (cv->store), search_iter))
 
317
        {
 
318
                do
 
319
                {
 
320
                        gtk_tree_model_get (GTK_TREE_MODEL (cv->store), search_iter, 
 
321
                                                                          COL_CHAN, &search_ch, -1);
 
322
                        if (family == search_ch->family && search_ch != avoid /*&&
 
323
                                 gtk_tree_store_iter_depth (cv->store, search_iter) == 0*/)
 
324
                                return TRUE;
 
325
                }
 
326
                while (gtk_tree_model_iter_next (GTK_TREE_MODEL (cv->store), search_iter));
 
327
        }
 
328
 
 
329
        return FALSE;
 
330
}
 
331
 
 
332
static chan *
 
333
chanview_add_real (chanview *cv, char *name, void *family, void *userdata,
 
334
                                                 gboolean allow_closure, int tag, GdkPixbuf *icon,
 
335
                                                 chan *ch, chan *avoid)
 
336
{
 
337
        GtkTreeIter parent_iter;
 
338
        GtkTreeIter iter;
 
339
        gboolean has_parent = FALSE;
 
340
 
 
341
        if (chanview_find_parent (cv, family, &parent_iter, avoid))
 
342
        {
 
343
                chanview_insert_sorted (cv, &iter, &parent_iter, userdata);
 
344
                has_parent = TRUE;
 
345
        } else
 
346
        {
 
347
                gtk_tree_store_append (cv->store, &iter, NULL);
 
348
        }
 
349
 
 
350
        if (!ch)
 
351
        {
 
352
                ch = calloc (1, sizeof (chan));
 
353
                ch->userdata = userdata;
 
354
                ch->family = family;
 
355
                ch->cv = cv;
 
356
                ch->allow_closure = allow_closure;
 
357
                ch->tag = tag;
 
358
                ch->icon = icon;
 
359
        }
 
360
        memcpy (&(ch->iter), &iter, sizeof (iter));
 
361
 
 
362
        gtk_tree_store_set (cv->store, &iter, COL_NAME, name, COL_CHAN, ch,
 
363
                                                          COL_PIXBUF, icon, -1);
 
364
 
 
365
        cv->size++;
 
366
        if (!has_parent)
 
367
                ch->impl = cv->func_add (cv, ch, name, NULL);
 
368
        else
 
369
                ch->impl = cv->func_add (cv, ch, name, &parent_iter);
 
370
 
 
371
        return ch;
 
372
}
 
373
 
 
374
chan *
 
375
chanview_add (chanview *cv, char *name, void *family, void *userdata, gboolean allow_closure, int tag, GdkPixbuf *icon)
 
376
{
 
377
        char *new_name;
 
378
        chan *ret;
 
379
 
 
380
        new_name = truncate_tab_name (name, cv->trunc_len);
 
381
 
 
382
        ret = chanview_add_real (cv, new_name, family, userdata, allow_closure, tag, icon, NULL, NULL);
 
383
 
 
384
        if (new_name != name)
 
385
                free (new_name);
 
386
 
 
387
        return ret;
 
388
}
 
389
 
 
390
int
 
391
chanview_get_size (chanview *cv)
 
392
{
 
393
        return cv->size;
 
394
}
 
395
 
 
396
GtkWidget *
 
397
chanview_get_box (chanview *cv)
 
398
{
 
399
        return cv->box;
 
400
}
 
401
 
 
402
void
 
403
chanview_move_focus (chanview *cv, gboolean relative, int num)
 
404
{
 
405
        cv->func_move_focus (cv, relative, num);
 
406
}
 
407
 
 
408
GtkOrientation
 
409
chanview_get_orientation (chanview *cv)
 
410
{
 
411
        return (cv->vertical ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL);
 
412
}
 
413
 
 
414
void
 
415
chanview_set_orientation (chanview *cv, gboolean vertical)
 
416
{
 
417
        if (vertical != cv->vertical)
 
418
        {
 
419
                cv->vertical = vertical;
 
420
                cv->func_change_orientation (cv);
 
421
        }
 
422
}
 
423
 
 
424
int
 
425
chan_get_tag (chan *ch)
 
426
{
 
427
        return ch->tag;
 
428
}
 
429
 
 
430
void *
 
431
chan_get_userdata (chan *ch)
 
432
{
 
433
        return ch->userdata;
 
434
}
 
435
 
 
436
void
 
437
chan_focus (chan *ch)
 
438
{
 
439
        if (ch->cv->focused == ch)
 
440
                return;
 
441
 
 
442
        ch->cv->func_focus (ch);
 
443
}
 
444
 
 
445
void
 
446
chan_move (chan *ch, int delta)
 
447
{
 
448
        ch->cv->func_move (ch, delta);
 
449
}
 
450
 
 
451
void
 
452
chan_move_family (chan *ch, int delta)
 
453
{
 
454
        ch->cv->func_move_family (ch, delta);
 
455
}
 
456
 
 
457
void
 
458
chan_set_color (chan *ch, PangoAttrList *list)
 
459
{
 
460
        gtk_tree_store_set (ch->cv->store, &ch->iter, COL_ATTR, list, -1);      
 
461
        ch->cv->func_set_color (ch, list);
 
462
}
 
463
 
 
464
void
 
465
chan_rename (chan *ch, char *name, int trunc_len)
 
466
{
 
467
        char *new_name;
 
468
 
 
469
        new_name = truncate_tab_name (name, trunc_len);
 
470
 
 
471
        gtk_tree_store_set (ch->cv->store, &ch->iter, COL_NAME, new_name, -1);
 
472
        ch->cv->func_rename (ch, new_name);
 
473
        ch->cv->trunc_len = trunc_len;
 
474
 
 
475
        if (new_name != name)
 
476
                free (new_name);
 
477
}
 
478
 
 
479
/* this thing is overly complicated */
 
480
 
 
481
static int
 
482
cv_find_number_of_chan (chanview *cv, chan *find_ch)
 
483
{
 
484
        GtkTreeIter iter, inner;
 
485
        chan *ch;
 
486
        int i = 0;
 
487
 
 
488
        if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (cv->store), &iter))
 
489
        {
 
490
                do
 
491
                {
 
492
                        gtk_tree_model_get (GTK_TREE_MODEL (cv->store), &iter, COL_CHAN, &ch, -1);
 
493
                        if (ch == find_ch)
 
494
                                return i;
 
495
                        i++;
 
496
 
 
497
                        if (gtk_tree_model_iter_children (GTK_TREE_MODEL (cv->store), &inner, &iter))
 
498
                        {
 
499
                                do
 
500
                                {
 
501
                                        gtk_tree_model_get (GTK_TREE_MODEL (cv->store), &inner, COL_CHAN, &ch, -1);
 
502
                                        if (ch == find_ch)
 
503
                                                return i;
 
504
                                        i++;
 
505
                                }
 
506
                                while (gtk_tree_model_iter_next (GTK_TREE_MODEL (cv->store), &inner));
 
507
                        }
 
508
                }
 
509
                while (gtk_tree_model_iter_next (GTK_TREE_MODEL (cv->store), &iter));
 
510
        }
 
511
 
 
512
        return 0;       /* WARNING */
 
513
}
 
514
 
 
515
/* this thing is overly complicated too */
 
516
 
 
517
static chan *
 
518
cv_find_chan_by_number (chanview *cv, int num)
 
519
{
 
520
        GtkTreeIter iter, inner;
 
521
        chan *ch;
 
522
        int i = 0;
 
523
 
 
524
        if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (cv->store), &iter))
 
525
        {
 
526
                do
 
527
                {
 
528
                        if (i == num)
 
529
                        {
 
530
                                gtk_tree_model_get (GTK_TREE_MODEL (cv->store), &iter, COL_CHAN, &ch, -1);
 
531
                                return ch;
 
532
                        }
 
533
                        i++;
 
534
 
 
535
                        if (gtk_tree_model_iter_children (GTK_TREE_MODEL (cv->store), &inner, &iter))
 
536
                        {
 
537
                                do
 
538
                                {
 
539
                                        if (i == num)
 
540
                                        {
 
541
                                                gtk_tree_model_get (GTK_TREE_MODEL (cv->store), &inner, COL_CHAN, &ch, -1);
 
542
                                                return ch;
 
543
                                        }
 
544
                                        i++;
 
545
                                }
 
546
                                while (gtk_tree_model_iter_next (GTK_TREE_MODEL (cv->store), &inner));
 
547
                        }
 
548
                }
 
549
                while (gtk_tree_model_iter_next (GTK_TREE_MODEL (cv->store), &iter));
 
550
        }
 
551
 
 
552
        return NULL;
 
553
}
 
554
 
 
555
static void
 
556
chan_emancipate_children (chan *ch)
 
557
{
 
558
        char *name;
 
559
        chan *childch;
 
560
        GtkTreeIter childiter;
 
561
        PangoAttrList *attr;
 
562
 
 
563
        while (gtk_tree_model_iter_children (GTK_TREE_MODEL (ch->cv->store), &childiter, &ch->iter))
 
564
        {
 
565
                /* remove and re-add all the children, but avoid using "ch" as parent */
 
566
                gtk_tree_model_get (GTK_TREE_MODEL (ch->cv->store), &childiter,
 
567
                                                                  COL_NAME, &name, COL_CHAN, &childch, COL_ATTR, &attr, -1);
 
568
                ch->cv->func_remove (childch);
 
569
                gtk_tree_store_remove (ch->cv->store, &childiter);
 
570
                ch->cv->size--;
 
571
                chanview_add_real (childch->cv, name, childch->family, childch->userdata, childch->allow_closure, childch->tag, childch->icon, childch, ch);
 
572
                if (attr)
 
573
                {
 
574
                        childch->cv->func_set_color (childch, attr);
 
575
                        pango_attr_list_unref (attr);
 
576
                }
 
577
                g_free (name);
 
578
        }
 
579
}
 
580
 
 
581
gboolean
 
582
chan_remove (chan *ch, gboolean force)
 
583
{
 
584
        chan *new_ch;
 
585
        int i, num;
 
586
        extern int xchat_is_quitting;
 
587
 
 
588
        if (xchat_is_quitting)  /* avoid lots of looping on exit */
 
589
                return TRUE;
 
590
 
 
591
        /* is this ch allowed to be closed while still having children? */
 
592
        if (!force &&
 
593
                 gtk_tree_model_iter_has_child (GTK_TREE_MODEL (ch->cv->store), &ch->iter) &&
 
594
                 !ch->allow_closure)
 
595
                return FALSE;
 
596
 
 
597
        chan_emancipate_children (ch);
 
598
        ch->cv->func_remove (ch);
 
599
 
 
600
        /* is it the focused one? */
 
601
        if (ch->cv->focused == ch)
 
602
        {
 
603
                ch->cv->focused = NULL;
 
604
 
 
605
                /* try to move the focus to some other valid channel */
 
606
                num = cv_find_number_of_chan (ch->cv, ch);
 
607
                /* move to the one left of the closing tab */
 
608
                new_ch = cv_find_chan_by_number (ch->cv, num - 1);
 
609
                if (new_ch && new_ch != ch)
 
610
                {
 
611
                        chan_focus (new_ch);    /* this'll will set ch->cv->focused for us too */
 
612
                } else
 
613
                {
 
614
                        /* if it fails, try focus from tab 0 and up */
 
615
                        for (i = 0; i < ch->cv->size; i++)
 
616
                        {
 
617
                                new_ch = cv_find_chan_by_number (ch->cv, i);
 
618
                                if (new_ch && new_ch != ch)
 
619
                                {
 
620
                                        chan_focus (new_ch);    /* this'll will set ch->cv->focused for us too */
 
621
                                        break;
 
622
                                }
 
623
                        }
 
624
                }
 
625
        }
 
626
 
 
627
        ch->cv->size--;
 
628
        gtk_tree_store_remove (ch->cv->store, &ch->iter);
 
629
        free (ch);
 
630
        return TRUE;
 
631
}
 
632
 
 
633
gboolean
 
634
chan_is_collapsed (chan *ch)
 
635
{
 
636
        return ch->cv->func_is_collapsed (ch);
 
637
}
 
638
 
 
639
chan *
 
640
chan_get_parent (chan *ch)
 
641
{
 
642
        return ch->cv->func_get_parent (ch);
 
643
}