1 /* HexChat
2 * Copyright (C) 1998-2010 Peter Zelezny.
3 * Copyright (C) 2009-2013 Berke Viktor.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 /* file included in chanview.c */
21
22 typedef struct
23 {
24 GtkWidget *outer; /* outer box */
25 GtkWidget *inner; /* inner box */
26 GtkWidget *b1; /* button1 */
27 GtkWidget *b2; /* button2 */
28 } tabview;
29
30 static void chanview_populate (chanview *cv);
31
32 /* ignore "toggled" signal? */
33 static int ignore_toggle = FALSE;
34 static int tab_left_is_moving = 0;
35 static int tab_right_is_moving = 0;
36
37 /* userdata for gobjects used here:
38 *
39 * tab (togglebuttons inside boxes):
40 * "u" userdata passed to tab-focus callback function (sess)
41 * "c" the tab's (chan *)
42 *
43 * box (family box)
44 * "f" family
45 *
46 */
47
48 /*
49 * GtkViewports request at least as much space as their children do.
50 * If we don't intervene here, the GtkViewport will be granted its
51 * request, even at the expense of resizing the top-level window.
52 */
53 static void
cv_tabs_sizerequest(GtkWidget * viewport,GtkRequisition * requisition,chanview * cv)54 cv_tabs_sizerequest (GtkWidget *viewport, GtkRequisition *requisition, chanview *cv)
55 {
56 if (!cv->vertical)
57 requisition->width = 1;
58 else
59 requisition->height = 1;
60 }
61
62 static void
cv_tabs_sizealloc(GtkWidget * widget,GtkAllocation * allocation,chanview * cv)63 cv_tabs_sizealloc (GtkWidget *widget, GtkAllocation *allocation, chanview *cv)
64 {
65 GdkWindow *parent_win;
66 GtkAdjustment *adj;
67 GtkWidget *inner;
68 gint viewport_size;
69
70 inner = ((tabview *)cv)->inner;
71 parent_win = gtk_widget_get_window (gtk_widget_get_parent (inner));
72
73 if (cv->vertical)
74 {
75 adj = gtk_viewport_get_vadjustment (GTK_VIEWPORT (gtk_widget_get_parent (inner)));
76 gdk_window_get_geometry (parent_win, 0, 0, 0, &viewport_size, 0);
77 } else
78 {
79 adj = gtk_viewport_get_hadjustment (GTK_VIEWPORT (gtk_widget_get_parent (inner)));
80 gdk_window_get_geometry (parent_win, 0, 0, &viewport_size, 0, 0);
81 }
82
83 if (gtk_adjustment_get_upper (adj) <= viewport_size)
84 {
85 gtk_widget_hide (((tabview *)cv)->b1);
86 gtk_widget_hide (((tabview *)cv)->b2);
87 } else
88 {
89 gtk_widget_show (((tabview *)cv)->b1);
90 gtk_widget_show (((tabview *)cv)->b2);
91 }
92 }
93
94 static gint
tab_search_offset(GtkWidget * inner,gint start_offset,gboolean forward,gboolean vertical)95 tab_search_offset (GtkWidget *inner, gint start_offset,
96 gboolean forward, gboolean vertical)
97 {
98 GList *boxes;
99 GList *tabs;
100 GtkWidget *box;
101 GtkWidget *button;
102 GtkAllocation allocation;
103 gint found;
104
105 boxes = gtk_container_get_children (GTK_CONTAINER (inner));
106 if (!forward && boxes)
107 boxes = g_list_last (boxes);
108
109 while (boxes)
110 {
111 box = (GtkWidget *)boxes->data;
112 boxes = (forward ? boxes->next : boxes->prev);
113
114 tabs = gtk_container_get_children (GTK_CONTAINER (box));
115 if (!forward && tabs)
116 tabs = g_list_last (tabs);
117
118 while (tabs)
119 {
120 button = (GtkWidget *)tabs->data;
121 tabs = (forward ? tabs->next : tabs->prev);
122
123 if (!GTK_IS_TOGGLE_BUTTON (button))
124 continue;
125
126 gtk_widget_get_allocation (button, &allocation);
127 found = (vertical ? allocation.y : allocation.x);
128 if ((forward && found > start_offset) ||
129 (!forward && found < start_offset))
130 return found;
131 }
132 }
133
134 return 0;
135 }
136
137 static void
tab_scroll_left_up_clicked(GtkWidget * widget,chanview * cv)138 tab_scroll_left_up_clicked (GtkWidget *widget, chanview *cv)
139 {
140 GtkAdjustment *adj;
141 gint viewport_size;
142 gfloat new_value;
143 GtkWidget *inner;
144 GdkWindow *parent_win;
145 gdouble i;
146
147 inner = ((tabview *)cv)->inner;
148 parent_win = gtk_widget_get_window (gtk_widget_get_parent (inner));
149
150 if (cv->vertical)
151 {
152 adj = gtk_viewport_get_vadjustment (GTK_VIEWPORT (gtk_widget_get_parent(inner)));
153 gdk_window_get_geometry (parent_win, 0, 0, 0, &viewport_size, 0);
154 } else
155 {
156 adj = gtk_viewport_get_hadjustment (GTK_VIEWPORT (gtk_widget_get_parent(inner)));
157 gdk_window_get_geometry (parent_win, 0, 0, &viewport_size, 0, 0);
158 }
159
160 new_value = tab_search_offset (inner, gtk_adjustment_get_value (adj), 0, cv->vertical);
161
162 if (new_value + viewport_size > gtk_adjustment_get_upper (adj))
163 new_value = gtk_adjustment_get_upper (adj) - viewport_size;
164
165 if (!tab_left_is_moving)
166 {
167 tab_left_is_moving = 1;
168
169 for (i = gtk_adjustment_get_value (adj); ((i > new_value) && (tab_left_is_moving)); i -= 0.1)
170 {
171 gtk_adjustment_set_value (adj, i);
172 while (g_main_context_pending (NULL))
173 g_main_context_iteration (NULL, TRUE);
174 }
175
176 gtk_adjustment_set_value (adj, new_value);
177
178 tab_left_is_moving = 0; /* hSP: set to false in case we didnt get stopped (the normal case) */
179 }
180 else
181 {
182 tab_left_is_moving = 0; /* hSP: jump directly to next element if user is clicking faster than we can scroll.. */
183 }
184 }
185
186 static void
tab_scroll_right_down_clicked(GtkWidget * widget,chanview * cv)187 tab_scroll_right_down_clicked (GtkWidget *widget, chanview *cv)
188 {
189 GtkAdjustment *adj;
190 gint viewport_size;
191 gfloat new_value;
192 GtkWidget *inner;
193 GdkWindow *parent_win;
194 gdouble i;
195
196 inner = ((tabview *)cv)->inner;
197 parent_win = gtk_widget_get_window (gtk_widget_get_parent (inner));
198
199 if (cv->vertical)
200 {
201 adj = gtk_viewport_get_vadjustment (GTK_VIEWPORT (gtk_widget_get_parent(inner)));
202 gdk_window_get_geometry (parent_win, 0, 0, 0, &viewport_size, 0);
203 } else
204 {
205 adj = gtk_viewport_get_hadjustment (GTK_VIEWPORT (gtk_widget_get_parent(inner)));
206 gdk_window_get_geometry (parent_win, 0, 0, &viewport_size, 0, 0);
207 }
208
209 new_value = tab_search_offset (inner, gtk_adjustment_get_value (adj), 1, cv->vertical);
210
211 if (new_value == 0 || new_value + viewport_size > gtk_adjustment_get_upper (adj))
212 new_value = gtk_adjustment_get_upper (adj) - viewport_size;
213
214 if (!tab_right_is_moving)
215 {
216 tab_right_is_moving = 1;
217
218 for (i = gtk_adjustment_get_value (adj); ((i < new_value) && (tab_right_is_moving)); i += 0.1)
219 {
220 gtk_adjustment_set_value (adj, i);
221 while (g_main_context_pending (NULL))
222 g_main_context_iteration (NULL, TRUE);
223 }
224
225 gtk_adjustment_set_value (adj, new_value);
226
227 tab_right_is_moving = 0; /* hSP: set to false in case we didnt get stopped (the normal case) */
228 }
229 else
230 {
231 tab_right_is_moving = 0; /* hSP: jump directly to next element if user is clicking faster than we can scroll.. */
232 }
233 }
234
235 static gboolean
tab_scroll_cb(GtkWidget * widget,GdkEventScroll * event,gpointer cv)236 tab_scroll_cb (GtkWidget *widget, GdkEventScroll *event, gpointer cv)
237 {
238 if (prefs.hex_gui_tab_scrollchans)
239 {
240 if (event->direction == GDK_SCROLL_DOWN)
241 mg_switch_page (1, 1);
242 else if (event->direction == GDK_SCROLL_UP)
243 mg_switch_page (1, -1);
244 }
245 else
246 {
247 /* mouse wheel scrolling */
248 if (event->direction == GDK_SCROLL_UP)
249 tab_scroll_left_up_clicked (widget, cv);
250 else if (event->direction == GDK_SCROLL_DOWN)
251 tab_scroll_right_down_clicked (widget, cv);
252 }
253
254 return FALSE;
255 }
256
257 static void
cv_tabs_xclick_cb(GtkWidget * button,chanview * cv)258 cv_tabs_xclick_cb (GtkWidget *button, chanview *cv)
259 {
260 cv->cb_xbutton (cv, cv->focused, cv->focused->tag, cv->focused->userdata);
261 }
262
263 /* make a Scroll (arrow) button */
264
265 static GtkWidget *
make_sbutton(GtkArrowType type,void * click_cb,void * userdata)266 make_sbutton (GtkArrowType type, void *click_cb, void *userdata)
267 {
268 GtkWidget *button, *arrow;
269
270 button = gtk_button_new ();
271 arrow = gtk_arrow_new (type, GTK_SHADOW_NONE);
272 gtk_container_add (GTK_CONTAINER (button), arrow);
273 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
274 g_signal_connect (G_OBJECT (button), "clicked",
275 G_CALLBACK (click_cb), userdata);
276 g_signal_connect (G_OBJECT (button), "scroll_event",
277 G_CALLBACK (tab_scroll_cb), userdata);
278 gtk_widget_show (arrow);
279
280 return button;
281 }
282
283 static void
cv_tabs_init(chanview * cv)284 cv_tabs_init (chanview *cv)
285 {
286 GtkWidget *box, *hbox = NULL;
287 GtkWidget *viewport;
288 GtkWidget *outer;
289 GtkWidget *button;
290
291 if (cv->vertical)
292 outer = gtk_vbox_new (0, 0);
293 else
294 outer = gtk_hbox_new (0, 0);
295 ((tabview *)cv)->outer = outer;
296 g_signal_connect (G_OBJECT (outer), "size_allocate",
297 G_CALLBACK (cv_tabs_sizealloc), cv);
298 /* gtk_container_set_border_width (GTK_CONTAINER (outer), 2);*/
299 gtk_widget_show (outer);
300
301 viewport = gtk_viewport_new (0, 0);
302 gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport), GTK_SHADOW_NONE);
303 g_signal_connect (G_OBJECT (viewport), "size_request",
304 G_CALLBACK (cv_tabs_sizerequest), cv);
305 g_signal_connect (G_OBJECT (viewport), "scroll_event",
306 G_CALLBACK (tab_scroll_cb), cv);
307 gtk_box_pack_start (GTK_BOX (outer), viewport, 1, 1, 0);
308 gtk_widget_show (viewport);
309
310 if (cv->vertical)
311 box = gtk_vbox_new (FALSE, 0);
312 else
313 box = gtk_hbox_new (FALSE, 0);
314 ((tabview *)cv)->inner = box;
315 gtk_container_add (GTK_CONTAINER (viewport), box);
316 gtk_widget_show (box);
317
318 /* if vertical, the buttons can be side by side */
319 if (cv->vertical)
320 {
321 hbox = gtk_hbox_new (FALSE, 0);
322 gtk_box_pack_start (GTK_BOX (outer), hbox, 0, 0, 0);
323 gtk_widget_show (hbox);
324 }
325
326 /* make the Scroll buttons */
327 ((tabview *)cv)->b2 = make_sbutton (cv->vertical ?
328 GTK_ARROW_UP : GTK_ARROW_LEFT,
329 tab_scroll_left_up_clicked,
330 cv);
331
332 ((tabview *)cv)->b1 = make_sbutton (cv->vertical ?
333 GTK_ARROW_DOWN : GTK_ARROW_RIGHT,
334 tab_scroll_right_down_clicked,
335 cv);
336
337 if (hbox)
338 {
339 gtk_container_add (GTK_CONTAINER (hbox), ((tabview *)cv)->b2);
340 gtk_container_add (GTK_CONTAINER (hbox), ((tabview *)cv)->b1);
341 } else
342 {
343 gtk_box_pack_start (GTK_BOX (outer), ((tabview *)cv)->b2, 0, 0, 0);
344 gtk_box_pack_start (GTK_BOX (outer), ((tabview *)cv)->b1, 0, 0, 0);
345 }
346
347 button = gtkutil_button (outer, GTK_STOCK_CLOSE, NULL, cv_tabs_xclick_cb,
348 cv, 0);
349 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
350 gtk_widget_set_can_focus (button, FALSE);
351
352 gtk_container_add (GTK_CONTAINER (cv->box), outer);
353 }
354
355 static void
cv_tabs_postinit(chanview * cv)356 cv_tabs_postinit (chanview *cv)
357 {
358 }
359
360 static void
tab_add_sorted(chanview * cv,GtkWidget * box,GtkWidget * tab,chan * ch)361 tab_add_sorted (chanview *cv, GtkWidget *box, GtkWidget *tab, chan *ch)
362 {
363 GList *list;
364 GtkWidget *child;
365 int i = 0;
366 void *b;
367
368 if (!cv->sorted)
369 {
370 gtk_box_pack_start (GTK_BOX (box), tab, 0, 0, 0);
371 gtk_widget_show (tab);
372 return;
373 }
374
375 /* sorting TODO:
376 * - move tab if renamed (dialogs) */
377
378 /* userdata, passed to mg_tabs_compare() */
379 b = ch->userdata;
380
381 list = gtk_container_get_children (GTK_CONTAINER (box));
382 while (list)
383 {
384 child = list->data;
385 if (!GTK_IS_SEPARATOR (child))
386 {
387 void *a = g_object_get_data (G_OBJECT (child), "u");
388
389 if (ch->tag == 0 && cv->cb_compare (a, b) > 0)
390 {
391 gtk_box_pack_start (GTK_BOX (box), tab, 0, 0, 0);
392 gtk_box_reorder_child (GTK_BOX (box), tab, ++i);
393 gtk_widget_show (tab);
394 return;
395 }
396 }
397 i++;
398 list = list->next;
399 }
400
401 /* append */
402 gtk_box_pack_start (GTK_BOX (box), tab, 0, 0, 0);
403 gtk_box_reorder_child (GTK_BOX (box), tab, i);
404 gtk_widget_show (tab);
405 }
406
407 /* remove empty boxes and separators */
408
409 static void
cv_tabs_prune(chanview * cv)410 cv_tabs_prune (chanview *cv)
411 {
412 GList *boxes, *children;
413 GtkWidget *box, *inner;
414 GtkWidget *child;
415 int empty;
416
417 inner = ((tabview *)cv)->inner;
418 boxes = gtk_container_get_children (GTK_CONTAINER (inner));
419 while (boxes)
420 {
421 child = boxes->data;
422 box = child;
423 boxes = boxes->next;
424
425 /* check if the box is empty (except a vseperator) */
426 empty = TRUE;
427 children = gtk_container_get_children (GTK_CONTAINER (box));
428 while (children)
429 {
430 if (!GTK_IS_SEPARATOR ((GtkWidget *)children->data))
431 {
432 empty = FALSE;
433 break;
434 }
435 children = children->next;
436 }
437
438 if (empty)
439 gtk_widget_destroy (box);
440 }
441 }
442
443 static void
tab_add_real(chanview * cv,GtkWidget * tab,chan * ch)444 tab_add_real (chanview *cv, GtkWidget *tab, chan *ch)
445 {
446 GList *boxes, *children;
447 GtkWidget *sep, *box, *inner;
448 GtkWidget *child;
449 int empty;
450
451 inner = ((tabview *)cv)->inner;
452 /* see if a family for this tab already exists */
453 boxes = gtk_container_get_children (GTK_CONTAINER (inner));
454 while (boxes)
455 {
456 child = boxes->data;
457 box = child;
458
459 if (g_object_get_data (G_OBJECT (box), "f") == ch->family)
460 {
461 tab_add_sorted (cv, box, tab, ch);
462 gtk_widget_queue_resize (gtk_widget_get_parent(inner));
463 return;
464 }
465
466 boxes = boxes->next;
467
468 /* check if the box is empty (except a vseperator) */
469 empty = TRUE;
470 children = gtk_container_get_children (GTK_CONTAINER (box));
471 while (children)
472 {
473 if (!GTK_IS_SEPARATOR ((GtkWidget *)children->data))
474 {
475 empty = FALSE;
476 break;
477 }
478 children = children->next;
479 }
480
481 if (empty)
482 gtk_widget_destroy (box);
483 }
484
485 /* create a new family box */
486 if (cv->vertical)
487 {
488 /* vertical */
489 box = gtk_vbox_new (FALSE, 0);
490 sep = gtk_hseparator_new ();
491 } else
492 {
493 /* horiz */
494 box = gtk_hbox_new (FALSE, 0);
495 sep = gtk_vseparator_new ();
496 }
497
498 gtk_box_pack_end (GTK_BOX (box), sep, 0, 0, 4);
499 gtk_widget_show (sep);
500 gtk_box_pack_start (GTK_BOX (inner), box, 0, 0, 0);
501 g_object_set_data (G_OBJECT (box), "f", ch->family);
502 gtk_box_pack_start (GTK_BOX (box), tab, 0, 0, 0);
503 gtk_widget_show (tab);
504 gtk_widget_show (box);
505 gtk_widget_queue_resize (gtk_widget_get_parent(inner));
506 }
507
508 static gboolean
tab_ignore_cb(GtkWidget * widget,GdkEventCrossing * event,gpointer user_data)509 tab_ignore_cb (GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
510 {
511 return TRUE;
512 }
513
514 /* called when a tab is clicked (button down) */
515
516 static void
tab_pressed_cb(GtkToggleButton * tab,chan * ch)517 tab_pressed_cb (GtkToggleButton *tab, chan *ch)
518 {
519 chan *old_tab;
520 int is_switching = TRUE;
521 chanview *cv = ch->cv;
522
523 ignore_toggle = TRUE;
524 /* de-activate the old tab */
525 old_tab = cv->focused;
526 if (old_tab && old_tab->impl)
527 {
528 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (old_tab->impl), FALSE);
529 if (old_tab == ch)
530 is_switching = FALSE;
531 }
532 gtk_toggle_button_set_active (tab, TRUE);
533 ignore_toggle = FALSE;
534 cv->focused = ch;
535
536 if (/*tab->active*/is_switching)
537 /* call the focus callback */
538 cv->cb_focus (cv, ch, ch->tag, ch->userdata);
539 }
540
541 /* called for keyboard tab toggles only */
542 static void
tab_toggled_cb(GtkToggleButton * tab,chan * ch)543 tab_toggled_cb (GtkToggleButton *tab, chan *ch)
544 {
545 if (ignore_toggle)
546 return;
547
548 /* activated a tab via keyboard */
549 tab_pressed_cb (tab, ch);
550 }
551
552 static gboolean
tab_click_cb(GtkWidget * wid,GdkEventButton * event,chan * ch)553 tab_click_cb (GtkWidget *wid, GdkEventButton *event, chan *ch)
554 {
555 return ch->cv->cb_contextmenu (ch->cv, ch, ch->tag, ch->userdata, event);
556 }
557
558 static void *
cv_tabs_add(chanview * cv,chan * ch,char * name,GtkTreeIter * parent)559 cv_tabs_add (chanview *cv, chan *ch, char *name, GtkTreeIter *parent)
560 {
561 GtkWidget *but;
562
563 but = gtk_toggle_button_new_with_label (name);
564 gtk_widget_set_name (but, "hexchat-tab");
565 g_object_set_data (G_OBJECT (but), "c", ch);
566 /* used to trap right-clicks */
567 g_signal_connect (G_OBJECT (but), "button_press_event",
568 G_CALLBACK (tab_click_cb), ch);
569 /* avoid prelights */
570 g_signal_connect (G_OBJECT (but), "enter_notify_event",
571 G_CALLBACK (tab_ignore_cb), NULL);
572 g_signal_connect (G_OBJECT (but), "leave_notify_event",
573 G_CALLBACK (tab_ignore_cb), NULL);
574 g_signal_connect (G_OBJECT (but), "pressed",
575 G_CALLBACK (tab_pressed_cb), ch);
576 /* for keyboard */
577 g_signal_connect (G_OBJECT (but), "toggled",
578 G_CALLBACK (tab_toggled_cb), ch);
579 g_object_set_data (G_OBJECT (but), "u", ch->userdata);
580
581 tab_add_real (cv, but, ch);
582
583 return but;
584 }
585
586 /* traverse all the family boxes of tabs
587 *
588 * A "group" is basically:
589 * GtkV/HBox
590 * `-GtkViewPort
591 * `-GtkV/HBox (inner box)
592 * `- GtkBox (family box)
593 * `- GtkToggleButton
594 * `- GtkToggleButton
595 * `- ...
596 * `- GtkBox
597 * `- GtkToggleButton
598 * `- GtkToggleButton
599 * `- ...
600 * `- ...
601 *
602 * */
603
604 static int
tab_group_for_each_tab(chanview * cv,int (* callback)(GtkWidget * tab,int num,int usernum),int usernum)605 tab_group_for_each_tab (chanview *cv,
606 int (*callback) (GtkWidget *tab, int num, int usernum),
607 int usernum)
608 {
609 GList *tabs;
610 GList *boxes;
611 GtkWidget *child;
612 GtkBox *innerbox;
613 int i;
614
615 innerbox = (GtkBox *) ((tabview *)cv)->inner;
616 boxes = gtk_container_get_children (GTK_CONTAINER (innerbox));
617 i = 0;
618 while (boxes)
619 {
620 child = boxes->data;
621 tabs = gtk_container_get_children (GTK_CONTAINER (child));
622
623 while (tabs)
624 {
625 child = tabs->data;
626
627 if (!GTK_IS_SEPARATOR (child))
628 {
629 if (callback (child, i, usernum) != -1)
630 return i;
631 i++;
632 }
633 tabs = tabs->next;
634 }
635
636 boxes = boxes->next;
637 }
638
639 return i;
640 }
641
642 static int
tab_check_focus_cb(GtkWidget * tab,int num,int unused)643 tab_check_focus_cb (GtkWidget *tab, int num, int unused)
644 {
645 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (tab)))
646 return num;
647
648 return -1;
649 }
650
651 /* returns the currently focused tab number */
652
653 static int
tab_group_get_cur_page(chanview * cv)654 tab_group_get_cur_page (chanview *cv)
655 {
656 return tab_group_for_each_tab (cv, tab_check_focus_cb, 0);
657 }
658
659 static void
cv_tabs_focus(chan * ch)660 cv_tabs_focus (chan *ch)
661 {
662 if (ch->impl)
663 /* focus the new one (tab_pressed_cb defocuses the old one) */
664 tab_pressed_cb (GTK_TOGGLE_BUTTON (ch->impl), ch);
665 }
666
667 static int
tab_focus_num_cb(GtkWidget * tab,int num,int want)668 tab_focus_num_cb (GtkWidget *tab, int num, int want)
669 {
670 if (num == want)
671 {
672 cv_tabs_focus (g_object_get_data (G_OBJECT (tab), "c"));
673 return 1;
674 }
675
676 return -1;
677 }
678
679 static void
cv_tabs_change_orientation(chanview * cv)680 cv_tabs_change_orientation (chanview *cv)
681 {
682 /* cleanup the old one */
683 if (cv->func_cleanup)
684 cv->func_cleanup (cv);
685
686 /* now rebuild a new tabbar or tree */
687 cv->func_init (cv);
688 chanview_populate (cv);
689 }
690
691 /* switch to the tab number specified */
692
693 static void
cv_tabs_move_focus(chanview * cv,gboolean relative,int num)694 cv_tabs_move_focus (chanview *cv, gboolean relative, int num)
695 {
696 int i, max;
697
698 if (relative)
699 {
700 max = cv->size;
701 i = tab_group_get_cur_page (cv) + num;
702 /* make it wrap around at both ends */
703 if (i < 0)
704 i = max - 1;
705 if (i >= max)
706 i = 0;
707 tab_group_for_each_tab (cv, tab_focus_num_cb, i);
708 return;
709 }
710
711 tab_group_for_each_tab (cv, tab_focus_num_cb, num);
712 }
713
714 static void
cv_tabs_remove(chan * ch)715 cv_tabs_remove (chan *ch)
716 {
717 gtk_widget_destroy (ch->impl);
718 ch->impl = NULL;
719
720 cv_tabs_prune (ch->cv);
721 }
722
723 static void
cv_tabs_move(chan * ch,int delta)724 cv_tabs_move (chan *ch, int delta)
725 {
726 int i = 0;
727 int pos = 0;
728 GList *list;
729 GtkWidget *parent = gtk_widget_get_parent(GTK_WIDGET (ch->impl));
730
731 for (list = gtk_container_get_children (GTK_CONTAINER (parent)); list; list = list->next)
732 {
733 GtkWidget *child_entry;
734
735 child_entry = list->data;
736 if (child_entry == ch->impl)
737 pos = i;
738
739 /* keep separator at end to not throw off our count */
740 if (GTK_IS_SEPARATOR (child_entry))
741 gtk_box_reorder_child (GTK_BOX (parent), child_entry, -1);
742 else
743 i++;
744 }
745
746 pos = (pos - delta) % i;
747 gtk_box_reorder_child (GTK_BOX (parent), ch->impl, pos);
748 }
749
750 static void
cv_tabs_move_family(chan * ch,int delta)751 cv_tabs_move_family (chan *ch, int delta)
752 {
753 int i, pos = 0;
754 GList *list;
755 GtkWidget *box = NULL;
756
757 /* find position of tab's family */
758 i = 0;
759 for (list = gtk_container_get_children (GTK_CONTAINER (((tabview *)ch->cv)->inner)); list; list = list->next)
760 {
761 GtkWidget *child_entry;
762 void *fam;
763
764 child_entry = list->data;
765 fam = g_object_get_data (G_OBJECT (child_entry), "f");
766 if (fam == ch->family)
767 {
768 box = child_entry;
769 pos = i;
770 }
771 i++;
772 }
773
774 pos = (pos - delta) % i;
775 gtk_box_reorder_child (GTK_BOX (gtk_widget_get_parent(box)), box, pos);
776 }
777
778 static void
cv_tabs_cleanup(chanview * cv)779 cv_tabs_cleanup (chanview *cv)
780 {
781 if (cv->box)
782 gtk_widget_destroy (((tabview *)cv)->outer);
783 }
784
785 static void
cv_tabs_set_color(chan * ch,PangoAttrList * list)786 cv_tabs_set_color (chan *ch, PangoAttrList *list)
787 {
788 gtk_label_set_attributes (GTK_LABEL (gtk_bin_get_child (GTK_BIN (ch->impl))), list);
789 }
790
791 static void
cv_tabs_rename(chan * ch,char * name)792 cv_tabs_rename (chan *ch, char *name)
793 {
794 PangoAttrList *attr;
795 GtkWidget *tab = ch->impl;
796
797 attr = gtk_label_get_attributes (GTK_LABEL (gtk_bin_get_child (GTK_BIN (tab))));
798 if (attr)
799 pango_attr_list_ref (attr);
800
801 gtk_button_set_label (GTK_BUTTON (tab), name);
802 gtk_widget_queue_resize (gtk_widget_get_parent(gtk_widget_get_parent(gtk_widget_get_parent(tab))));
803
804 if (attr)
805 {
806 gtk_label_set_attributes (GTK_LABEL (gtk_bin_get_child (GTK_BIN (tab))), attr);
807 pango_attr_list_unref (attr);
808 }
809 }
810
811 static gboolean
cv_tabs_is_collapsed(chan * ch)812 cv_tabs_is_collapsed (chan *ch)
813 {
814 return FALSE;
815 }
816
817 static chan *
cv_tabs_get_parent(chan * ch)818 cv_tabs_get_parent (chan *ch)
819 {
820 return NULL;
821 }
822