2026-01-05 23:12:38 -07:00
|
|
|
/* ZoiteChat
|
2013-03-31 21:44:48 +02:00
|
|
|
* Copyright (C) 1998-2010 Peter Zelezny.
|
|
|
|
|
* Copyright (C) 2009-2013 Berke Viktor.
|
|
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
|
*/
|
|
|
|
|
|
2011-02-24 04:14:30 +01:00
|
|
|
/* file included in chanview.c */
|
|
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *outer; /* outer box */
|
|
|
|
|
GtkWidget *inner; /* inner box */
|
|
|
|
|
GtkWidget *b1; /* button1 */
|
|
|
|
|
GtkWidget *b2; /* button2 */
|
|
|
|
|
} tabview;
|
|
|
|
|
|
Added per-file ICON_* macros with GTK3 icon-name mappings and GTK2 stock fallbacks across GTK UI modules like banlist, DCC, editlist, ignore, URL grabber, notify, text events, tray menu, chanview tabs, and join dialog UI.
Updated GTK helper usages to reference the new ICON_* (and label) macros so GTK3 builds no longer pass stock IDs to button/icon helpers or dialogs, including banlist buttons, DCC windows, rawlog actions, notify dialog/buttons, pevent dialog buttons, tray menu items, and join dialog image helper usage.
2026-01-30 09:23:52 -07:00
|
|
|
#define ICON_CHANVIEW_CLOSE "window-close"
|
|
|
|
|
|
2011-02-24 04:14:30 +01:00
|
|
|
static void chanview_populate (chanview *cv);
|
|
|
|
|
|
|
|
|
|
/* ignore "toggled" signal? */
|
|
|
|
|
static int ignore_toggle = FALSE;
|
|
|
|
|
static int tab_left_is_moving = 0;
|
|
|
|
|
static int tab_right_is_moving = 0;
|
|
|
|
|
|
2026-03-02 19:42:48 -07:00
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
GtkAdjustment *adj;
|
|
|
|
|
gdouble current_value;
|
|
|
|
|
gdouble target_value;
|
|
|
|
|
gint direction;
|
|
|
|
|
gdouble step_size;
|
|
|
|
|
guint source_id;
|
|
|
|
|
int *moving_flag;
|
|
|
|
|
gboolean is_left;
|
|
|
|
|
} tab_scroll_animation;
|
|
|
|
|
|
|
|
|
|
static tab_scroll_animation *tab_left_animation;
|
|
|
|
|
static tab_scroll_animation *tab_right_animation;
|
|
|
|
|
|
2011-02-24 04:14:30 +01:00
|
|
|
/* userdata for gobjects used here:
|
|
|
|
|
*
|
|
|
|
|
* tab (togglebuttons inside boxes):
|
|
|
|
|
* "u" userdata passed to tab-focus callback function (sess)
|
|
|
|
|
* "c" the tab's (chan *)
|
|
|
|
|
*
|
|
|
|
|
* box (family box)
|
|
|
|
|
* "f" family
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
2026-01-30 19:23:34 -07:00
|
|
|
static inline gint
|
|
|
|
|
cv_tabs_get_viewport_size (GdkWindow *parent_win, gboolean vertical)
|
|
|
|
|
{
|
|
|
|
|
gint viewport_size = 0;
|
|
|
|
|
|
|
|
|
|
if (vertical)
|
|
|
|
|
viewport_size = gdk_window_get_height (parent_win);
|
|
|
|
|
else
|
|
|
|
|
viewport_size = gdk_window_get_width (parent_win);
|
|
|
|
|
|
|
|
|
|
return viewport_size;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-24 04:14:30 +01:00
|
|
|
/*
|
|
|
|
|
* GtkViewports request at least as much space as their children do.
|
|
|
|
|
* If we don't intervene here, the GtkViewport will be granted its
|
|
|
|
|
* request, even at the expense of resizing the top-level window.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
cv_tabs_sizerequest (GtkWidget *viewport, GtkRequisition *requisition, chanview *cv)
|
|
|
|
|
{
|
|
|
|
|
if (!cv->vertical)
|
|
|
|
|
requisition->width = 1;
|
|
|
|
|
else
|
|
|
|
|
requisition->height = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
cv_tabs_sizealloc (GtkWidget *widget, GtkAllocation *allocation, chanview *cv)
|
|
|
|
|
{
|
2014-07-19 13:36:13 +10:00
|
|
|
GdkWindow *parent_win;
|
2011-02-24 04:14:30 +01:00
|
|
|
GtkAdjustment *adj;
|
|
|
|
|
GtkWidget *inner;
|
|
|
|
|
gint viewport_size;
|
|
|
|
|
|
|
|
|
|
inner = ((tabview *)cv)->inner;
|
2014-07-19 13:36:13 +10:00
|
|
|
parent_win = gtk_widget_get_window (gtk_widget_get_parent (inner));
|
2011-02-24 04:14:30 +01:00
|
|
|
|
|
|
|
|
if (cv->vertical)
|
|
|
|
|
{
|
2013-10-05 22:21:04 -04:00
|
|
|
adj = gtk_viewport_get_vadjustment (GTK_VIEWPORT (gtk_widget_get_parent (inner)));
|
2011-02-24 04:14:30 +01:00
|
|
|
} else
|
|
|
|
|
{
|
2013-10-05 22:21:04 -04:00
|
|
|
adj = gtk_viewport_get_hadjustment (GTK_VIEWPORT (gtk_widget_get_parent (inner)));
|
2011-02-24 04:14:30 +01:00
|
|
|
}
|
|
|
|
|
|
2026-01-30 19:23:34 -07:00
|
|
|
viewport_size = cv_tabs_get_viewport_size (parent_win, cv->vertical);
|
|
|
|
|
|
2013-10-05 22:21:04 -04:00
|
|
|
if (gtk_adjustment_get_upper (adj) <= viewport_size)
|
2011-02-24 04:14:30 +01:00
|
|
|
{
|
|
|
|
|
gtk_widget_hide (((tabview *)cv)->b1);
|
|
|
|
|
gtk_widget_hide (((tabview *)cv)->b2);
|
|
|
|
|
} else
|
|
|
|
|
{
|
|
|
|
|
gtk_widget_show (((tabview *)cv)->b1);
|
|
|
|
|
gtk_widget_show (((tabview *)cv)->b2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gint
|
|
|
|
|
tab_search_offset (GtkWidget *inner, gint start_offset,
|
|
|
|
|
gboolean forward, gboolean vertical)
|
|
|
|
|
{
|
|
|
|
|
GList *boxes;
|
|
|
|
|
GList *tabs;
|
|
|
|
|
GtkWidget *box;
|
|
|
|
|
GtkWidget *button;
|
2013-10-06 22:17:45 -04:00
|
|
|
GtkAllocation allocation;
|
2011-02-24 04:14:30 +01:00
|
|
|
gint found;
|
|
|
|
|
|
2013-10-05 22:21:04 -04:00
|
|
|
boxes = gtk_container_get_children (GTK_CONTAINER (inner));
|
2011-02-24 04:14:30 +01:00
|
|
|
if (!forward && boxes)
|
|
|
|
|
boxes = g_list_last (boxes);
|
|
|
|
|
|
|
|
|
|
while (boxes)
|
|
|
|
|
{
|
2013-10-05 22:21:04 -04:00
|
|
|
box = (GtkWidget *)boxes->data;
|
2011-02-24 04:14:30 +01:00
|
|
|
boxes = (forward ? boxes->next : boxes->prev);
|
|
|
|
|
|
2013-10-05 22:21:04 -04:00
|
|
|
tabs = gtk_container_get_children (GTK_CONTAINER (box));
|
2011-02-24 04:14:30 +01:00
|
|
|
if (!forward && tabs)
|
|
|
|
|
tabs = g_list_last (tabs);
|
|
|
|
|
|
|
|
|
|
while (tabs)
|
|
|
|
|
{
|
2013-10-05 22:21:04 -04:00
|
|
|
button = (GtkWidget *)tabs->data;
|
2011-02-24 04:14:30 +01:00
|
|
|
tabs = (forward ? tabs->next : tabs->prev);
|
|
|
|
|
|
|
|
|
|
if (!GTK_IS_TOGGLE_BUTTON (button))
|
|
|
|
|
continue;
|
|
|
|
|
|
2013-10-06 22:17:45 -04:00
|
|
|
gtk_widget_get_allocation (button, &allocation);
|
|
|
|
|
found = (vertical ? allocation.y : allocation.x);
|
2011-02-24 04:14:30 +01:00
|
|
|
if ((forward && found > start_offset) ||
|
|
|
|
|
(!forward && found < start_offset))
|
|
|
|
|
return found;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-02 19:42:48 -07:00
|
|
|
static gboolean
|
|
|
|
|
tab_scroll_animation_tick (gpointer userdata)
|
|
|
|
|
{
|
|
|
|
|
tab_scroll_animation *animation = userdata;
|
|
|
|
|
gboolean reached_target;
|
|
|
|
|
|
|
|
|
|
animation->current_value += animation->step_size * animation->direction;
|
|
|
|
|
|
|
|
|
|
if (animation->direction < 0)
|
|
|
|
|
reached_target = animation->current_value <= animation->target_value;
|
|
|
|
|
else
|
|
|
|
|
reached_target = animation->current_value >= animation->target_value;
|
|
|
|
|
|
|
|
|
|
if (reached_target)
|
|
|
|
|
animation->current_value = animation->target_value;
|
|
|
|
|
|
|
|
|
|
gtk_adjustment_set_value (animation->adj, animation->current_value);
|
|
|
|
|
|
|
|
|
|
if (!reached_target)
|
|
|
|
|
return G_SOURCE_CONTINUE;
|
|
|
|
|
|
|
|
|
|
*animation->moving_flag = 0;
|
|
|
|
|
animation->source_id = 0;
|
|
|
|
|
|
|
|
|
|
if (animation->is_left)
|
|
|
|
|
tab_left_animation = NULL;
|
|
|
|
|
else
|
|
|
|
|
tab_right_animation = NULL;
|
|
|
|
|
|
|
|
|
|
g_object_unref (animation->adj);
|
|
|
|
|
g_free (animation);
|
|
|
|
|
|
|
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tab_scroll_animation_cancel (tab_scroll_animation **animation)
|
|
|
|
|
{
|
|
|
|
|
if (*animation == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if ((*animation)->source_id != 0)
|
|
|
|
|
g_source_remove ((*animation)->source_id);
|
|
|
|
|
|
|
|
|
|
*(*animation)->moving_flag = 0;
|
|
|
|
|
g_object_unref ((*animation)->adj);
|
|
|
|
|
g_free (*animation);
|
|
|
|
|
*animation = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tab_scroll_animation_start (tab_scroll_animation **slot, GtkAdjustment *adj,
|
|
|
|
|
gdouble current_value, gdouble target_value,
|
|
|
|
|
gint direction, int *moving_flag,
|
|
|
|
|
gboolean is_left)
|
|
|
|
|
{
|
|
|
|
|
tab_scroll_animation *animation;
|
|
|
|
|
gdouble distance;
|
|
|
|
|
gdouble frames;
|
|
|
|
|
|
|
|
|
|
distance = target_value - current_value;
|
|
|
|
|
if (distance < 0.0)
|
|
|
|
|
distance = -distance;
|
|
|
|
|
|
|
|
|
|
if (distance <= 0.0)
|
|
|
|
|
{
|
|
|
|
|
gtk_adjustment_set_value (adj, target_value);
|
|
|
|
|
*moving_flag = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
animation = g_new0 (tab_scroll_animation, 1);
|
|
|
|
|
animation->adj = g_object_ref (adj);
|
|
|
|
|
animation->current_value = current_value;
|
|
|
|
|
animation->target_value = target_value;
|
|
|
|
|
animation->direction = direction;
|
|
|
|
|
frames = 12.0;
|
|
|
|
|
animation->step_size = distance / MAX (1.0, frames);
|
|
|
|
|
animation->moving_flag = moving_flag;
|
|
|
|
|
animation->is_left = is_left;
|
|
|
|
|
|
|
|
|
|
*moving_flag = 1;
|
|
|
|
|
animation->source_id = g_timeout_add (16, tab_scroll_animation_tick, animation);
|
|
|
|
|
*slot = animation;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-24 04:14:30 +01:00
|
|
|
static void
|
|
|
|
|
tab_scroll_left_up_clicked (GtkWidget *widget, chanview *cv)
|
|
|
|
|
{
|
|
|
|
|
GtkAdjustment *adj;
|
|
|
|
|
gint viewport_size;
|
|
|
|
|
gfloat new_value;
|
|
|
|
|
GtkWidget *inner;
|
2013-10-05 22:21:04 -04:00
|
|
|
GdkWindow *parent_win;
|
2011-02-24 04:14:30 +01:00
|
|
|
|
|
|
|
|
inner = ((tabview *)cv)->inner;
|
2013-10-05 22:21:04 -04:00
|
|
|
parent_win = gtk_widget_get_window (gtk_widget_get_parent (inner));
|
2011-02-24 04:14:30 +01:00
|
|
|
|
|
|
|
|
if (cv->vertical)
|
|
|
|
|
{
|
2013-10-05 22:21:04 -04:00
|
|
|
adj = gtk_viewport_get_vadjustment (GTK_VIEWPORT (gtk_widget_get_parent(inner)));
|
2011-02-24 04:14:30 +01:00
|
|
|
} else
|
|
|
|
|
{
|
2013-10-05 22:21:04 -04:00
|
|
|
adj = gtk_viewport_get_hadjustment (GTK_VIEWPORT (gtk_widget_get_parent(inner)));
|
2011-02-24 04:14:30 +01:00
|
|
|
}
|
|
|
|
|
|
2026-01-30 19:23:34 -07:00
|
|
|
viewport_size = cv_tabs_get_viewport_size (parent_win, cv->vertical);
|
|
|
|
|
|
2013-10-06 22:17:45 -04:00
|
|
|
new_value = tab_search_offset (inner, gtk_adjustment_get_value (adj), 0, cv->vertical);
|
2011-02-24 04:14:30 +01:00
|
|
|
|
2013-10-06 22:17:45 -04:00
|
|
|
if (new_value + viewport_size > gtk_adjustment_get_upper (adj))
|
|
|
|
|
new_value = gtk_adjustment_get_upper (adj) - viewport_size;
|
2011-02-24 04:14:30 +01:00
|
|
|
|
2026-03-02 19:42:48 -07:00
|
|
|
if (tab_left_is_moving)
|
2011-02-24 04:14:30 +01:00
|
|
|
{
|
2026-03-02 19:42:48 -07:00
|
|
|
tab_scroll_animation_cancel (&tab_left_animation);
|
|
|
|
|
return;
|
2011-02-24 04:14:30 +01:00
|
|
|
}
|
2026-03-02 19:42:48 -07:00
|
|
|
|
|
|
|
|
tab_scroll_animation_start (&tab_left_animation, adj,
|
|
|
|
|
gtk_adjustment_get_value (adj), new_value,
|
|
|
|
|
-1, &tab_left_is_moving, TRUE);
|
2011-02-24 04:14:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tab_scroll_right_down_clicked (GtkWidget *widget, chanview *cv)
|
|
|
|
|
{
|
|
|
|
|
GtkAdjustment *adj;
|
|
|
|
|
gint viewport_size;
|
|
|
|
|
gfloat new_value;
|
|
|
|
|
GtkWidget *inner;
|
2013-10-05 22:21:04 -04:00
|
|
|
GdkWindow *parent_win;
|
2011-02-24 04:14:30 +01:00
|
|
|
|
|
|
|
|
inner = ((tabview *)cv)->inner;
|
2013-10-05 22:21:04 -04:00
|
|
|
parent_win = gtk_widget_get_window (gtk_widget_get_parent (inner));
|
2011-02-24 04:14:30 +01:00
|
|
|
|
|
|
|
|
if (cv->vertical)
|
|
|
|
|
{
|
2013-10-05 22:21:04 -04:00
|
|
|
adj = gtk_viewport_get_vadjustment (GTK_VIEWPORT (gtk_widget_get_parent(inner)));
|
2011-02-24 04:14:30 +01:00
|
|
|
} else
|
|
|
|
|
{
|
2013-10-05 22:21:04 -04:00
|
|
|
adj = gtk_viewport_get_hadjustment (GTK_VIEWPORT (gtk_widget_get_parent(inner)));
|
2011-02-24 04:14:30 +01:00
|
|
|
}
|
|
|
|
|
|
2026-01-30 19:23:34 -07:00
|
|
|
viewport_size = cv_tabs_get_viewport_size (parent_win, cv->vertical);
|
|
|
|
|
|
2013-10-06 22:17:45 -04:00
|
|
|
new_value = tab_search_offset (inner, gtk_adjustment_get_value (adj), 1, cv->vertical);
|
2011-02-24 04:14:30 +01:00
|
|
|
|
2013-10-06 22:17:45 -04:00
|
|
|
if (new_value == 0 || new_value + viewport_size > gtk_adjustment_get_upper (adj))
|
|
|
|
|
new_value = gtk_adjustment_get_upper (adj) - viewport_size;
|
2011-02-24 04:14:30 +01:00
|
|
|
|
2026-03-02 19:42:48 -07:00
|
|
|
if (tab_right_is_moving)
|
2011-02-24 04:14:30 +01:00
|
|
|
{
|
2026-03-02 19:42:48 -07:00
|
|
|
tab_scroll_animation_cancel (&tab_right_animation);
|
|
|
|
|
return;
|
2011-02-24 04:14:30 +01:00
|
|
|
}
|
2026-03-02 19:42:48 -07:00
|
|
|
|
|
|
|
|
tab_scroll_animation_start (&tab_right_animation, adj,
|
|
|
|
|
gtk_adjustment_get_value (adj), new_value,
|
|
|
|
|
1, &tab_right_is_moving, FALSE);
|
2011-02-24 04:14:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
tab_scroll_cb (GtkWidget *widget, GdkEventScroll *event, gpointer cv)
|
|
|
|
|
{
|
2013-10-08 18:16:10 -04:00
|
|
|
if (prefs.hex_gui_tab_scrollchans)
|
|
|
|
|
{
|
|
|
|
|
if (event->direction == GDK_SCROLL_DOWN)
|
|
|
|
|
mg_switch_page (1, 1);
|
|
|
|
|
else if (event->direction == GDK_SCROLL_UP)
|
|
|
|
|
mg_switch_page (1, -1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* mouse wheel scrolling */
|
|
|
|
|
if (event->direction == GDK_SCROLL_UP)
|
|
|
|
|
tab_scroll_left_up_clicked (widget, cv);
|
|
|
|
|
else if (event->direction == GDK_SCROLL_DOWN)
|
|
|
|
|
tab_scroll_right_down_clicked (widget, cv);
|
|
|
|
|
}
|
2011-02-24 04:14:30 +01:00
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
cv_tabs_xclick_cb (GtkWidget *button, chanview *cv)
|
|
|
|
|
{
|
|
|
|
|
cv->cb_xbutton (cv, cv->focused, cv->focused->tag, cv->focused->userdata);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* make a Scroll (arrow) button */
|
|
|
|
|
|
|
|
|
|
static GtkWidget *
|
|
|
|
|
make_sbutton (GtkArrowType type, void *click_cb, void *userdata)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *button, *arrow;
|
2026-01-30 19:00:01 -07:00
|
|
|
const char *icon_name = "pan-end-symbolic";
|
2011-02-24 04:14:30 +01:00
|
|
|
|
|
|
|
|
button = gtk_button_new ();
|
2026-01-30 19:00:01 -07:00
|
|
|
switch (type)
|
|
|
|
|
{
|
|
|
|
|
case GTK_ARROW_UP:
|
|
|
|
|
icon_name = "pan-up-symbolic";
|
|
|
|
|
break;
|
|
|
|
|
case GTK_ARROW_DOWN:
|
|
|
|
|
icon_name = "pan-down-symbolic";
|
|
|
|
|
break;
|
|
|
|
|
case GTK_ARROW_LEFT:
|
|
|
|
|
icon_name = "pan-start-symbolic";
|
|
|
|
|
break;
|
|
|
|
|
case GTK_ARROW_RIGHT:
|
|
|
|
|
default:
|
|
|
|
|
icon_name = "pan-end-symbolic";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
arrow = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON);
|
2011-02-24 04:14:30 +01:00
|
|
|
gtk_container_add (GTK_CONTAINER (button), arrow);
|
|
|
|
|
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
|
|
|
|
|
g_signal_connect (G_OBJECT (button), "clicked",
|
|
|
|
|
G_CALLBACK (click_cb), userdata);
|
|
|
|
|
g_signal_connect (G_OBJECT (button), "scroll_event",
|
|
|
|
|
G_CALLBACK (tab_scroll_cb), userdata);
|
|
|
|
|
gtk_widget_show (arrow);
|
|
|
|
|
|
|
|
|
|
return button;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
cv_tabs_init (chanview *cv)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *box, *hbox = NULL;
|
|
|
|
|
GtkWidget *viewport;
|
|
|
|
|
GtkWidget *outer;
|
|
|
|
|
GtkWidget *button;
|
|
|
|
|
|
|
|
|
|
if (cv->vertical)
|
2026-01-23 21:28:32 -07:00
|
|
|
{
|
2026-02-05 01:59:15 -07:00
|
|
|
outer = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0);
|
2026-01-23 21:28:32 -07:00
|
|
|
}
|
2011-02-24 04:14:30 +01:00
|
|
|
else
|
2026-01-23 21:28:32 -07:00
|
|
|
{
|
2026-02-05 01:59:15 -07:00
|
|
|
outer = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0);
|
2026-01-23 21:28:32 -07:00
|
|
|
}
|
2011-02-24 04:14:30 +01:00
|
|
|
((tabview *)cv)->outer = outer;
|
|
|
|
|
g_signal_connect (G_OBJECT (outer), "size_allocate",
|
|
|
|
|
G_CALLBACK (cv_tabs_sizealloc), cv);
|
|
|
|
|
gtk_widget_show (outer);
|
|
|
|
|
|
|
|
|
|
viewport = gtk_viewport_new (0, 0);
|
|
|
|
|
gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport), GTK_SHADOW_NONE);
|
|
|
|
|
g_signal_connect (G_OBJECT (viewport), "size_request",
|
|
|
|
|
G_CALLBACK (cv_tabs_sizerequest), cv);
|
|
|
|
|
g_signal_connect (G_OBJECT (viewport), "scroll_event",
|
|
|
|
|
G_CALLBACK (tab_scroll_cb), cv);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (outer), viewport, 1, 1, 0);
|
|
|
|
|
gtk_widget_show (viewport);
|
|
|
|
|
|
|
|
|
|
if (cv->vertical)
|
2026-01-23 21:28:32 -07:00
|
|
|
{
|
2026-02-05 01:59:15 -07:00
|
|
|
box = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0);
|
2026-01-23 21:28:32 -07:00
|
|
|
}
|
2011-02-24 04:14:30 +01:00
|
|
|
else
|
2026-01-23 21:28:32 -07:00
|
|
|
{
|
2026-02-05 01:59:15 -07:00
|
|
|
box = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0);
|
2026-01-23 21:28:32 -07:00
|
|
|
}
|
2011-02-24 04:14:30 +01:00
|
|
|
((tabview *)cv)->inner = box;
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (viewport), box);
|
|
|
|
|
gtk_widget_show (box);
|
|
|
|
|
|
|
|
|
|
/* if vertical, the buttons can be side by side */
|
|
|
|
|
if (cv->vertical)
|
|
|
|
|
{
|
2026-02-05 01:59:15 -07:00
|
|
|
hbox = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0);
|
2011-02-24 04:14:30 +01:00
|
|
|
gtk_box_pack_start (GTK_BOX (outer), hbox, 0, 0, 0);
|
|
|
|
|
gtk_widget_show (hbox);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* make the Scroll buttons */
|
|
|
|
|
((tabview *)cv)->b2 = make_sbutton (cv->vertical ?
|
|
|
|
|
GTK_ARROW_UP : GTK_ARROW_LEFT,
|
|
|
|
|
tab_scroll_left_up_clicked,
|
|
|
|
|
cv);
|
|
|
|
|
|
|
|
|
|
((tabview *)cv)->b1 = make_sbutton (cv->vertical ?
|
|
|
|
|
GTK_ARROW_DOWN : GTK_ARROW_RIGHT,
|
|
|
|
|
tab_scroll_right_down_clicked,
|
|
|
|
|
cv);
|
|
|
|
|
|
|
|
|
|
if (hbox)
|
|
|
|
|
{
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (hbox), ((tabview *)cv)->b2);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (hbox), ((tabview *)cv)->b1);
|
|
|
|
|
} else
|
|
|
|
|
{
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (outer), ((tabview *)cv)->b2, 0, 0, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (outer), ((tabview *)cv)->b1, 0, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
Added per-file ICON_* macros with GTK3 icon-name mappings and GTK2 stock fallbacks across GTK UI modules like banlist, DCC, editlist, ignore, URL grabber, notify, text events, tray menu, chanview tabs, and join dialog UI.
Updated GTK helper usages to reference the new ICON_* (and label) macros so GTK3 builds no longer pass stock IDs to button/icon helpers or dialogs, including banlist buttons, DCC windows, rawlog actions, notify dialog/buttons, pevent dialog buttons, tray menu items, and join dialog image helper usage.
2026-01-30 09:23:52 -07:00
|
|
|
button = gtkutil_button (outer, ICON_CHANVIEW_CLOSE, NULL, cv_tabs_xclick_cb,
|
2011-02-24 04:14:30 +01:00
|
|
|
cv, 0);
|
|
|
|
|
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
|
2013-10-05 22:21:04 -04:00
|
|
|
gtk_widget_set_can_focus (button, FALSE);
|
2011-02-24 04:14:30 +01:00
|
|
|
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (cv->box), outer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
cv_tabs_postinit (chanview *cv)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tab_add_sorted (chanview *cv, GtkWidget *box, GtkWidget *tab, chan *ch)
|
|
|
|
|
{
|
|
|
|
|
GList *list;
|
2013-10-05 22:21:04 -04:00
|
|
|
GtkWidget *child;
|
2011-02-24 04:14:30 +01:00
|
|
|
int i = 0;
|
|
|
|
|
void *b;
|
|
|
|
|
|
|
|
|
|
if (!cv->sorted)
|
|
|
|
|
{
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (box), tab, 0, 0, 0);
|
|
|
|
|
gtk_widget_show (tab);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* sorting TODO:
|
|
|
|
|
* - move tab if renamed (dialogs) */
|
|
|
|
|
|
|
|
|
|
/* userdata, passed to mg_tabs_compare() */
|
|
|
|
|
b = ch->userdata;
|
|
|
|
|
|
2013-10-05 22:21:04 -04:00
|
|
|
list = gtk_container_get_children (GTK_CONTAINER (box));
|
2011-02-24 04:14:30 +01:00
|
|
|
while (list)
|
|
|
|
|
{
|
|
|
|
|
child = list->data;
|
2013-10-05 22:21:04 -04:00
|
|
|
if (!GTK_IS_SEPARATOR (child))
|
2011-02-24 04:14:30 +01:00
|
|
|
{
|
2013-10-05 22:21:04 -04:00
|
|
|
void *a = g_object_get_data (G_OBJECT (child), "u");
|
2011-02-24 04:14:30 +01:00
|
|
|
|
|
|
|
|
if (ch->tag == 0 && cv->cb_compare (a, b) > 0)
|
|
|
|
|
{
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (box), tab, 0, 0, 0);
|
2014-05-06 21:36:08 -07:00
|
|
|
gtk_box_reorder_child (GTK_BOX (box), tab, ++i);
|
2011-02-24 04:14:30 +01:00
|
|
|
gtk_widget_show (tab);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
i++;
|
|
|
|
|
list = list->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* append */
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (box), tab, 0, 0, 0);
|
|
|
|
|
gtk_box_reorder_child (GTK_BOX (box), tab, i);
|
|
|
|
|
gtk_widget_show (tab);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* remove empty boxes and separators */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
cv_tabs_prune (chanview *cv)
|
|
|
|
|
{
|
|
|
|
|
GList *boxes, *children;
|
|
|
|
|
GtkWidget *box, *inner;
|
2013-10-05 22:21:04 -04:00
|
|
|
GtkWidget *child;
|
2011-02-24 04:14:30 +01:00
|
|
|
int empty;
|
|
|
|
|
|
|
|
|
|
inner = ((tabview *)cv)->inner;
|
2013-10-05 22:21:04 -04:00
|
|
|
boxes = gtk_container_get_children (GTK_CONTAINER (inner));
|
2011-02-24 04:14:30 +01:00
|
|
|
while (boxes)
|
|
|
|
|
{
|
|
|
|
|
child = boxes->data;
|
2013-10-05 22:21:04 -04:00
|
|
|
box = child;
|
2011-02-24 04:14:30 +01:00
|
|
|
boxes = boxes->next;
|
|
|
|
|
|
|
|
|
|
/* check if the box is empty (except a vseperator) */
|
|
|
|
|
empty = TRUE;
|
2013-10-05 22:21:04 -04:00
|
|
|
children = gtk_container_get_children (GTK_CONTAINER (box));
|
2011-02-24 04:14:30 +01:00
|
|
|
while (children)
|
|
|
|
|
{
|
2013-10-05 22:21:04 -04:00
|
|
|
if (!GTK_IS_SEPARATOR ((GtkWidget *)children->data))
|
2011-02-24 04:14:30 +01:00
|
|
|
{
|
|
|
|
|
empty = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
children = children->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (empty)
|
|
|
|
|
gtk_widget_destroy (box);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tab_add_real (chanview *cv, GtkWidget *tab, chan *ch)
|
|
|
|
|
{
|
|
|
|
|
GList *boxes, *children;
|
|
|
|
|
GtkWidget *sep, *box, *inner;
|
2013-10-05 22:21:04 -04:00
|
|
|
GtkWidget *child;
|
2011-02-24 04:14:30 +01:00
|
|
|
int empty;
|
|
|
|
|
|
|
|
|
|
inner = ((tabview *)cv)->inner;
|
|
|
|
|
/* see if a family for this tab already exists */
|
2013-10-05 22:21:04 -04:00
|
|
|
boxes = gtk_container_get_children (GTK_CONTAINER (inner));
|
2011-02-24 04:14:30 +01:00
|
|
|
while (boxes)
|
|
|
|
|
{
|
|
|
|
|
child = boxes->data;
|
2013-10-05 22:21:04 -04:00
|
|
|
box = child;
|
2011-02-24 04:14:30 +01:00
|
|
|
|
|
|
|
|
if (g_object_get_data (G_OBJECT (box), "f") == ch->family)
|
|
|
|
|
{
|
|
|
|
|
tab_add_sorted (cv, box, tab, ch);
|
2013-10-05 22:21:04 -04:00
|
|
|
gtk_widget_queue_resize (gtk_widget_get_parent(inner));
|
2011-02-24 04:14:30 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boxes = boxes->next;
|
|
|
|
|
|
|
|
|
|
/* check if the box is empty (except a vseperator) */
|
|
|
|
|
empty = TRUE;
|
2013-10-05 22:21:04 -04:00
|
|
|
children = gtk_container_get_children (GTK_CONTAINER (box));
|
2011-02-24 04:14:30 +01:00
|
|
|
while (children)
|
|
|
|
|
{
|
2013-10-05 22:21:04 -04:00
|
|
|
if (!GTK_IS_SEPARATOR ((GtkWidget *)children->data))
|
2011-02-24 04:14:30 +01:00
|
|
|
{
|
|
|
|
|
empty = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
children = children->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (empty)
|
|
|
|
|
gtk_widget_destroy (box);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* create a new family box */
|
|
|
|
|
if (cv->vertical)
|
|
|
|
|
{
|
|
|
|
|
/* vertical */
|
2026-02-05 01:59:15 -07:00
|
|
|
box = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0);
|
2026-01-30 17:48:25 -07:00
|
|
|
sep = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
|
2011-02-24 04:14:30 +01:00
|
|
|
} else
|
|
|
|
|
{
|
|
|
|
|
/* horiz */
|
2026-02-05 01:59:15 -07:00
|
|
|
box = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0);
|
2026-01-30 18:56:29 -07:00
|
|
|
sep = gtk_separator_new (GTK_ORIENTATION_VERTICAL);
|
2011-02-24 04:14:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gtk_box_pack_end (GTK_BOX (box), sep, 0, 0, 4);
|
|
|
|
|
gtk_widget_show (sep);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (inner), box, 0, 0, 0);
|
|
|
|
|
g_object_set_data (G_OBJECT (box), "f", ch->family);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (box), tab, 0, 0, 0);
|
|
|
|
|
gtk_widget_show (tab);
|
|
|
|
|
gtk_widget_show (box);
|
2013-10-05 22:21:04 -04:00
|
|
|
gtk_widget_queue_resize (gtk_widget_get_parent(inner));
|
2011-02-24 04:14:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
tab_ignore_cb (GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* called when a tab is clicked (button down) */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tab_pressed_cb (GtkToggleButton *tab, chan *ch)
|
|
|
|
|
{
|
|
|
|
|
chan *old_tab;
|
|
|
|
|
int is_switching = TRUE;
|
|
|
|
|
chanview *cv = ch->cv;
|
|
|
|
|
|
|
|
|
|
ignore_toggle = TRUE;
|
|
|
|
|
/* de-activate the old tab */
|
|
|
|
|
old_tab = cv->focused;
|
|
|
|
|
if (old_tab && old_tab->impl)
|
|
|
|
|
{
|
|
|
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (old_tab->impl), FALSE);
|
|
|
|
|
if (old_tab == ch)
|
|
|
|
|
is_switching = FALSE;
|
|
|
|
|
}
|
|
|
|
|
gtk_toggle_button_set_active (tab, TRUE);
|
|
|
|
|
ignore_toggle = FALSE;
|
|
|
|
|
cv->focused = ch;
|
|
|
|
|
|
2026-02-25 02:01:11 -07:00
|
|
|
if (is_switching)
|
2011-02-24 04:14:30 +01:00
|
|
|
/* call the focus callback */
|
|
|
|
|
cv->cb_focus (cv, ch, ch->tag, ch->userdata);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* called for keyboard tab toggles only */
|
|
|
|
|
static void
|
|
|
|
|
tab_toggled_cb (GtkToggleButton *tab, chan *ch)
|
|
|
|
|
{
|
|
|
|
|
if (ignore_toggle)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* activated a tab via keyboard */
|
|
|
|
|
tab_pressed_cb (tab, ch);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
tab_click_cb (GtkWidget *wid, GdkEventButton *event, chan *ch)
|
|
|
|
|
{
|
|
|
|
|
return ch->cv->cb_contextmenu (ch->cv, ch, ch->tag, ch->userdata, event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void *
|
|
|
|
|
cv_tabs_add (chanview *cv, chan *ch, char *name, GtkTreeIter *parent)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *but;
|
|
|
|
|
|
|
|
|
|
but = gtk_toggle_button_new_with_label (name);
|
2026-01-05 23:12:38 -07:00
|
|
|
gtk_widget_set_name (but, "zoitechat-tab");
|
2011-02-24 04:14:30 +01:00
|
|
|
g_object_set_data (G_OBJECT (but), "c", ch);
|
|
|
|
|
/* used to trap right-clicks */
|
|
|
|
|
g_signal_connect (G_OBJECT (but), "button_press_event",
|
|
|
|
|
G_CALLBACK (tab_click_cb), ch);
|
|
|
|
|
/* avoid prelights */
|
|
|
|
|
g_signal_connect (G_OBJECT (but), "enter_notify_event",
|
|
|
|
|
G_CALLBACK (tab_ignore_cb), NULL);
|
|
|
|
|
g_signal_connect (G_OBJECT (but), "leave_notify_event",
|
|
|
|
|
G_CALLBACK (tab_ignore_cb), NULL);
|
|
|
|
|
g_signal_connect (G_OBJECT (but), "pressed",
|
|
|
|
|
G_CALLBACK (tab_pressed_cb), ch);
|
|
|
|
|
/* for keyboard */
|
|
|
|
|
g_signal_connect (G_OBJECT (but), "toggled",
|
|
|
|
|
G_CALLBACK (tab_toggled_cb), ch);
|
|
|
|
|
g_object_set_data (G_OBJECT (but), "u", ch->userdata);
|
|
|
|
|
|
|
|
|
|
tab_add_real (cv, but, ch);
|
|
|
|
|
|
|
|
|
|
return but;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* traverse all the family boxes of tabs
|
|
|
|
|
*
|
|
|
|
|
* A "group" is basically:
|
|
|
|
|
* GtkV/HBox
|
|
|
|
|
* `-GtkViewPort
|
|
|
|
|
* `-GtkV/HBox (inner box)
|
|
|
|
|
* `- GtkBox (family box)
|
|
|
|
|
* `- GtkToggleButton
|
|
|
|
|
* `- GtkToggleButton
|
|
|
|
|
* `- ...
|
|
|
|
|
* `- GtkBox
|
|
|
|
|
* `- GtkToggleButton
|
|
|
|
|
* `- GtkToggleButton
|
|
|
|
|
* `- ...
|
|
|
|
|
* `- ...
|
|
|
|
|
*
|
|
|
|
|
* */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
tab_group_for_each_tab (chanview *cv,
|
|
|
|
|
int (*callback) (GtkWidget *tab, int num, int usernum),
|
|
|
|
|
int usernum)
|
|
|
|
|
{
|
|
|
|
|
GList *tabs;
|
|
|
|
|
GList *boxes;
|
2013-10-05 22:21:04 -04:00
|
|
|
GtkWidget *child;
|
2011-02-24 04:14:30 +01:00
|
|
|
GtkBox *innerbox;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
innerbox = (GtkBox *) ((tabview *)cv)->inner;
|
2013-10-05 22:21:04 -04:00
|
|
|
boxes = gtk_container_get_children (GTK_CONTAINER (innerbox));
|
2011-02-24 04:14:30 +01:00
|
|
|
i = 0;
|
|
|
|
|
while (boxes)
|
|
|
|
|
{
|
|
|
|
|
child = boxes->data;
|
2013-10-05 22:21:04 -04:00
|
|
|
tabs = gtk_container_get_children (GTK_CONTAINER (child));
|
2011-02-24 04:14:30 +01:00
|
|
|
|
|
|
|
|
while (tabs)
|
|
|
|
|
{
|
|
|
|
|
child = tabs->data;
|
|
|
|
|
|
2013-10-05 22:21:04 -04:00
|
|
|
if (!GTK_IS_SEPARATOR (child))
|
2011-02-24 04:14:30 +01:00
|
|
|
{
|
2013-10-05 22:21:04 -04:00
|
|
|
if (callback (child, i, usernum) != -1)
|
2011-02-24 04:14:30 +01:00
|
|
|
return i;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
tabs = tabs->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boxes = boxes->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
tab_check_focus_cb (GtkWidget *tab, int num, int unused)
|
|
|
|
|
{
|
2013-10-06 22:17:45 -04:00
|
|
|
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (tab)))
|
2011-02-24 04:14:30 +01:00
|
|
|
return num;
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* returns the currently focused tab number */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
tab_group_get_cur_page (chanview *cv)
|
|
|
|
|
{
|
|
|
|
|
return tab_group_for_each_tab (cv, tab_check_focus_cb, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
cv_tabs_focus (chan *ch)
|
|
|
|
|
{
|
|
|
|
|
if (ch->impl)
|
|
|
|
|
/* focus the new one (tab_pressed_cb defocuses the old one) */
|
|
|
|
|
tab_pressed_cb (GTK_TOGGLE_BUTTON (ch->impl), ch);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
tab_focus_num_cb (GtkWidget *tab, int num, int want)
|
|
|
|
|
{
|
|
|
|
|
if (num == want)
|
|
|
|
|
{
|
|
|
|
|
cv_tabs_focus (g_object_get_data (G_OBJECT (tab), "c"));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
cv_tabs_change_orientation (chanview *cv)
|
|
|
|
|
{
|
|
|
|
|
/* cleanup the old one */
|
|
|
|
|
if (cv->func_cleanup)
|
|
|
|
|
cv->func_cleanup (cv);
|
|
|
|
|
|
|
|
|
|
/* now rebuild a new tabbar or tree */
|
|
|
|
|
cv->func_init (cv);
|
|
|
|
|
chanview_populate (cv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* switch to the tab number specified */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
cv_tabs_move_focus (chanview *cv, gboolean relative, int num)
|
|
|
|
|
{
|
|
|
|
|
int i, max;
|
|
|
|
|
|
|
|
|
|
if (relative)
|
|
|
|
|
{
|
|
|
|
|
max = cv->size;
|
|
|
|
|
i = tab_group_get_cur_page (cv) + num;
|
|
|
|
|
/* make it wrap around at both ends */
|
|
|
|
|
if (i < 0)
|
|
|
|
|
i = max - 1;
|
|
|
|
|
if (i >= max)
|
|
|
|
|
i = 0;
|
|
|
|
|
tab_group_for_each_tab (cv, tab_focus_num_cb, i);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tab_group_for_each_tab (cv, tab_focus_num_cb, num);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
cv_tabs_remove (chan *ch)
|
|
|
|
|
{
|
|
|
|
|
gtk_widget_destroy (ch->impl);
|
|
|
|
|
ch->impl = NULL;
|
|
|
|
|
|
|
|
|
|
cv_tabs_prune (ch->cv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
cv_tabs_move (chan *ch, int delta)
|
|
|
|
|
{
|
2013-10-15 01:10:03 -04:00
|
|
|
int i = 0;
|
|
|
|
|
int pos = 0;
|
2011-02-24 04:14:30 +01:00
|
|
|
GList *list;
|
2013-10-05 22:21:04 -04:00
|
|
|
GtkWidget *parent = gtk_widget_get_parent(GTK_WIDGET (ch->impl));
|
2011-02-24 04:14:30 +01:00
|
|
|
|
2013-10-05 22:21:04 -04:00
|
|
|
for (list = gtk_container_get_children (GTK_CONTAINER (parent)); list; list = list->next)
|
2011-02-24 04:14:30 +01:00
|
|
|
{
|
2013-10-05 22:21:04 -04:00
|
|
|
GtkWidget *child_entry;
|
2011-02-24 04:14:30 +01:00
|
|
|
|
|
|
|
|
child_entry = list->data;
|
2013-10-05 22:21:04 -04:00
|
|
|
if (child_entry == ch->impl)
|
2011-02-24 04:14:30 +01:00
|
|
|
pos = i;
|
2013-10-15 01:10:03 -04:00
|
|
|
|
|
|
|
|
/* keep separator at end to not throw off our count */
|
|
|
|
|
if (GTK_IS_SEPARATOR (child_entry))
|
|
|
|
|
gtk_box_reorder_child (GTK_BOX (parent), child_entry, -1);
|
|
|
|
|
else
|
|
|
|
|
i++;
|
2011-02-24 04:14:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pos = (pos - delta) % i;
|
|
|
|
|
gtk_box_reorder_child (GTK_BOX (parent), ch->impl, pos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
cv_tabs_move_family (chan *ch, int delta)
|
|
|
|
|
{
|
|
|
|
|
int i, pos = 0;
|
|
|
|
|
GList *list;
|
|
|
|
|
GtkWidget *box = NULL;
|
|
|
|
|
|
|
|
|
|
/* find position of tab's family */
|
|
|
|
|
i = 0;
|
2013-10-05 22:21:04 -04:00
|
|
|
for (list = gtk_container_get_children (GTK_CONTAINER (((tabview *)ch->cv)->inner)); list; list = list->next)
|
2011-02-24 04:14:30 +01:00
|
|
|
{
|
2013-10-05 22:21:04 -04:00
|
|
|
GtkWidget *child_entry;
|
2011-02-24 04:14:30 +01:00
|
|
|
void *fam;
|
|
|
|
|
|
|
|
|
|
child_entry = list->data;
|
2013-10-05 22:21:04 -04:00
|
|
|
fam = g_object_get_data (G_OBJECT (child_entry), "f");
|
2011-02-24 04:14:30 +01:00
|
|
|
if (fam == ch->family)
|
|
|
|
|
{
|
2013-10-05 22:21:04 -04:00
|
|
|
box = child_entry;
|
2011-02-24 04:14:30 +01:00
|
|
|
pos = i;
|
|
|
|
|
}
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pos = (pos - delta) % i;
|
2013-10-05 22:21:04 -04:00
|
|
|
gtk_box_reorder_child (GTK_BOX (gtk_widget_get_parent(box)), box, pos);
|
2011-02-24 04:14:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
cv_tabs_cleanup (chanview *cv)
|
|
|
|
|
{
|
|
|
|
|
if (cv->box)
|
|
|
|
|
gtk_widget_destroy (((tabview *)cv)->outer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
cv_tabs_set_color (chan *ch, PangoAttrList *list)
|
|
|
|
|
{
|
2013-10-06 22:17:45 -04:00
|
|
|
gtk_label_set_attributes (GTK_LABEL (gtk_bin_get_child (GTK_BIN (ch->impl))), list);
|
2011-02-24 04:14:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
cv_tabs_rename (chan *ch, char *name)
|
|
|
|
|
{
|
|
|
|
|
PangoAttrList *attr;
|
|
|
|
|
GtkWidget *tab = ch->impl;
|
|
|
|
|
|
2013-10-06 22:17:45 -04:00
|
|
|
attr = gtk_label_get_attributes (GTK_LABEL (gtk_bin_get_child (GTK_BIN (tab))));
|
2011-02-24 04:14:30 +01:00
|
|
|
if (attr)
|
|
|
|
|
pango_attr_list_ref (attr);
|
|
|
|
|
|
|
|
|
|
gtk_button_set_label (GTK_BUTTON (tab), name);
|
2013-10-05 22:21:04 -04:00
|
|
|
gtk_widget_queue_resize (gtk_widget_get_parent(gtk_widget_get_parent(gtk_widget_get_parent(tab))));
|
2011-02-24 04:14:30 +01:00
|
|
|
|
|
|
|
|
if (attr)
|
|
|
|
|
{
|
2013-10-06 22:17:45 -04:00
|
|
|
gtk_label_set_attributes (GTK_LABEL (gtk_bin_get_child (GTK_BIN (tab))), attr);
|
2011-02-24 04:14:30 +01:00
|
|
|
pango_attr_list_unref (attr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
cv_tabs_is_collapsed (chan *ch)
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static chan *
|
|
|
|
|
cv_tabs_get_parent (chan *ch)
|
|
|
|
|
{
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|