pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Make PurpleIRCv3Connection Derivable
15 months ago, Gary Kramlich
7af8ab97086d
Make PurpleIRCv3Connection Derivable
This is going to be necessary for the protocol plugin to be subclassed.
Testing Done:
Compiled and connected to my local ergo instance.
Reviewed at https://reviews.imfreedom.org/r/2187/
/* pidgin
*
* Pidgin is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
* source distribution.
*
* 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 Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
#include
<glib/gi18n-lib.h>
#include
<gtk/gtk.h>
#include
<purple.h>
#include
"gtksavedstatuses.h"
#include
"pidginiconname.h"
enum
{
SS_MENU_ENTRY_TYPE_PRIMITIVE
,
SS_MENU_ENTRY_TYPE_SAVEDSTATUS
};
enum
{
/* _SSMenuEntryType */
SS_MENU_TYPE_COLUMN
,
/*
* This is a GdkPixbuf (the other columns are strings).
* This column is visible.
*/
SS_MENU_ICON_COLUMN
,
/* The text displayed on the status box. This column is visible. */
SS_MENU_TEXT_COLUMN
,
/*
* This value depends on SS_MENU_TYPE_COLUMN. For _SAVEDSTATUS types,
* this is the creation time. For _PRIMITIVE types,
* this is the PurpleStatusPrimitive.
*/
SS_MENU_DATA_COLUMN
,
/*
* This is the emblem to use for this status
*/
SS_MENU_EMBLEM_COLUMN
,
/*
* And whether or not that emblem is visible
*/
SS_MENU_EMBLEM_VISIBLE_COLUMN
,
SS_MENU_NUM_COLUMNS
};
static
void
status_menu_cb
(
GtkComboBox
*
widget
,
void
(
*
callback
)(
PurpleSavedStatus
*
))
{
GtkTreeIter
iter
;
int
type
;
gpointer
data
;
PurpleSavedStatus
*
status
=
NULL
;
if
(
!
gtk_combo_box_get_active_iter
(
widget
,
&
iter
))
return
;
gtk_tree_model_get
(
gtk_combo_box_get_model
(
widget
),
&
iter
,
SS_MENU_TYPE_COLUMN
,
&
type
,
SS_MENU_DATA_COLUMN
,
&
data
,
-1
);
if
(
type
==
SS_MENU_ENTRY_TYPE_PRIMITIVE
)
{
PurpleStatusPrimitive
primitive
=
GPOINTER_TO_INT
(
data
);
status
=
purple_savedstatus_find_transient_by_type_and_message
(
primitive
,
NULL
);
if
(
status
==
NULL
)
status
=
purple_savedstatus_new
(
NULL
,
primitive
);
}
else
if
(
type
==
SS_MENU_ENTRY_TYPE_SAVEDSTATUS
)
status
=
purple_savedstatus_find_by_creation_time
(
GPOINTER_TO_INT
(
data
));
callback
(
status
);
}
static
gint
saved_status_sort_alphabetically_func
(
gconstpointer
a
,
gconstpointer
b
)
{
const
PurpleSavedStatus
*
saved_status_a
=
a
;
const
PurpleSavedStatus
*
saved_status_b
=
b
;
return
g_utf8_collate
(
purple_savedstatus_get_title
(
saved_status_a
),
purple_savedstatus_get_title
(
saved_status_b
));
}
static
gboolean
pidgin_status_menu_add_primitive
(
GtkListStore
*
model
,
G_GNUC_UNUSED
GtkWidget
*
w
,
PurpleStatusPrimitive
primitive
,
PurpleSavedStatus
*
current_status
)
{
GtkTreeIter
iter
;
gboolean
currently_selected
=
FALSE
;
gtk_list_store_append
(
model
,
&
iter
);
gtk_list_store_set
(
model
,
&
iter
,
SS_MENU_TYPE_COLUMN
,
SS_MENU_ENTRY_TYPE_PRIMITIVE
,
SS_MENU_ICON_COLUMN
,
pidgin_icon_name_from_status_primitive
(
primitive
,
NULL
),
SS_MENU_TEXT_COLUMN
,
purple_primitive_get_name_from_type
(
primitive
),
SS_MENU_DATA_COLUMN
,
GINT_TO_POINTER
(
primitive
),
SS_MENU_EMBLEM_VISIBLE_COLUMN
,
FALSE
,
-1
);
if
(
purple_savedstatus_is_transient
(
current_status
)
&&
!
purple_savedstatus_has_substatuses
(
current_status
)
&&
purple_savedstatus_get_primitive_type
(
current_status
)
==
primitive
)
currently_selected
=
TRUE
;
return
currently_selected
;
}
static
void
pidgin_status_menu_update_iter
(
GtkWidget
*
combobox
,
GtkListStore
*
store
,
GtkTreeIter
*
iter
,
PurpleSavedStatus
*
status
)
{
PurpleStatusPrimitive
primitive
;
if
(
store
==
NULL
)
store
=
GTK_LIST_STORE
(
gtk_combo_box_get_model
(
GTK_COMBO_BOX
(
combobox
)));
primitive
=
purple_savedstatus_get_primitive_type
(
status
);
gtk_list_store_set
(
store
,
iter
,
SS_MENU_TYPE_COLUMN
,
SS_MENU_ENTRY_TYPE_SAVEDSTATUS
,
SS_MENU_ICON_COLUMN
,
pidgin_icon_name_from_status_primitive
(
primitive
,
NULL
),
SS_MENU_TEXT_COLUMN
,
purple_savedstatus_get_title
(
status
),
SS_MENU_DATA_COLUMN
,
GINT_TO_POINTER
(
purple_savedstatus_get_creation_time
(
status
)),
SS_MENU_EMBLEM_COLUMN
,
"document-save"
,
SS_MENU_EMBLEM_VISIBLE_COLUMN
,
TRUE
,
-1
);
}
static
gboolean
pidgin_status_menu_find_iter
(
GtkListStore
*
store
,
GtkTreeIter
*
iter
,
PurpleSavedStatus
*
find
)
{
int
type
;
gpointer
data
;
time_t
creation_time
=
purple_savedstatus_get_creation_time
(
find
);
GtkTreeModel
*
model
=
GTK_TREE_MODEL
(
store
);
if
(
!
gtk_tree_model_get_iter_first
(
model
,
iter
))
return
FALSE
;
do
{
gtk_tree_model_get
(
model
,
iter
,
SS_MENU_TYPE_COLUMN
,
&
type
,
SS_MENU_DATA_COLUMN
,
&
data
,
-1
);
if
(
type
==
SS_MENU_ENTRY_TYPE_PRIMITIVE
)
continue
;
if
(
GPOINTER_TO_INT
(
data
)
==
creation_time
)
return
TRUE
;
}
while
(
gtk_tree_model_iter_next
(
model
,
iter
));
return
FALSE
;
}
static
void
savedstatus_added_cb
(
PurpleSavedStatus
*
status
,
GtkWidget
*
combobox
)
{
GtkListStore
*
store
;
GtkTreeIter
iter
;
if
(
purple_savedstatus_is_transient
(
status
))
return
;
store
=
GTK_LIST_STORE
(
gtk_combo_box_get_model
(
GTK_COMBO_BOX
(
combobox
)));
gtk_list_store_append
(
store
,
&
iter
);
pidgin_status_menu_update_iter
(
combobox
,
store
,
&
iter
,
status
);
}
static
void
savedstatus_deleted_cb
(
PurpleSavedStatus
*
status
,
GtkWidget
*
combobox
)
{
GtkListStore
*
store
;
GtkTreeIter
iter
;
if
(
purple_savedstatus_is_transient
(
status
))
return
;
store
=
GTK_LIST_STORE
(
gtk_combo_box_get_model
(
GTK_COMBO_BOX
(
combobox
)));
if
(
pidgin_status_menu_find_iter
(
store
,
&
iter
,
status
))
gtk_list_store_remove
(
store
,
&
iter
);
}
static
void
savedstatus_modified_cb
(
PurpleSavedStatus
*
status
,
GtkWidget
*
combobox
)
{
GtkListStore
*
store
;
GtkTreeIter
iter
;
if
(
purple_savedstatus_is_transient
(
status
))
return
;
store
=
GTK_LIST_STORE
(
gtk_combo_box_get_model
(
GTK_COMBO_BOX
(
combobox
)));
if
(
pidgin_status_menu_find_iter
(
store
,
&
iter
,
status
))
pidgin_status_menu_update_iter
(
combobox
,
store
,
&
iter
,
status
);
}
GtkWidget
*
pidgin_status_menu
(
PurpleSavedStatus
*
current_status
,
GCallback
callback
)
{
GtkWidget
*
combobox
;
GtkListStore
*
model
;
GList
*
sorted
,
*
cur
;
int
i
=
0
;
int
index
=
-1
;
GtkTreeIter
iter
;
GtkCellRenderer
*
text_rend
;
GtkCellRenderer
*
icon_rend
;
GtkCellRenderer
*
emblem_rend
;
model
=
gtk_list_store_new
(
SS_MENU_NUM_COLUMNS
,
G_TYPE_INT
,
G_TYPE_STRING
,
G_TYPE_STRING
,
G_TYPE_POINTER
,
G_TYPE_STRING
,
G_TYPE_BOOLEAN
);
combobox
=
gtk_combo_box_new
();
if
(
pidgin_status_menu_add_primitive
(
model
,
combobox
,
PURPLE_STATUS_AVAILABLE
,
current_status
))
index
=
i
;
i
++
;
if
(
pidgin_status_menu_add_primitive
(
model
,
combobox
,
PURPLE_STATUS_AWAY
,
current_status
))
index
=
i
;
i
++
;
if
(
pidgin_status_menu_add_primitive
(
model
,
combobox
,
PURPLE_STATUS_INVISIBLE
,
current_status
))
index
=
i
;
i
++
;
if
(
pidgin_status_menu_add_primitive
(
model
,
combobox
,
PURPLE_STATUS_OFFLINE
,
current_status
))
index
=
i
;
i
++
;
sorted
=
g_list_copy
((
GList
*
)
purple_savedstatuses_get_all
());
sorted
=
g_list_sort
(
sorted
,
saved_status_sort_alphabetically_func
);
for
(
cur
=
sorted
;
cur
;
cur
=
cur
->
next
)
{
PurpleSavedStatus
*
status
=
(
PurpleSavedStatus
*
)
cur
->
data
;
if
(
!
purple_savedstatus_is_transient
(
status
))
{
gtk_list_store_append
(
model
,
&
iter
);
pidgin_status_menu_update_iter
(
combobox
,
model
,
&
iter
,
status
);
if
(
status
==
current_status
)
index
=
i
;
i
++
;
}
}
g_list_free
(
sorted
);
gtk_combo_box_set_model
(
GTK_COMBO_BOX
(
combobox
),
GTK_TREE_MODEL
(
model
));
text_rend
=
gtk_cell_renderer_text_new
();
icon_rend
=
gtk_cell_renderer_pixbuf_new
();
emblem_rend
=
gtk_cell_renderer_pixbuf_new
();
gtk_cell_layout_pack_start
(
GTK_CELL_LAYOUT
(
combobox
),
icon_rend
,
FALSE
);
gtk_cell_layout_pack_start
(
GTK_CELL_LAYOUT
(
combobox
),
text_rend
,
TRUE
);
gtk_cell_layout_pack_start
(
GTK_CELL_LAYOUT
(
combobox
),
emblem_rend
,
FALSE
);
gtk_cell_layout_set_attributes
(
GTK_CELL_LAYOUT
(
combobox
),
icon_rend
,
"icon-name"
,
SS_MENU_ICON_COLUMN
,
NULL
);
gtk_cell_layout_set_attributes
(
GTK_CELL_LAYOUT
(
combobox
),
text_rend
,
"markup"
,
SS_MENU_TEXT_COLUMN
,
NULL
);
gtk_cell_layout_set_attributes
(
GTK_CELL_LAYOUT
(
combobox
),
emblem_rend
,
"icon-name"
,
SS_MENU_EMBLEM_COLUMN
,
"visible"
,
SS_MENU_EMBLEM_VISIBLE_COLUMN
,
NULL
);
g_object_set
(
text_rend
,
"ellipsize"
,
PANGO_ELLIPSIZE_END
,
NULL
);
gtk_combo_box_set_active
(
GTK_COMBO_BOX
(
combobox
),
index
);
g_signal_connect
(
G_OBJECT
(
combobox
),
"changed"
,
G_CALLBACK
(
status_menu_cb
),
callback
);
/* Make sure the list is updated dynamically when a substatus is changed/deleted
* or a new one is added. */
purple_signal_connect
(
purple_savedstatuses_get_handle
(),
"savedstatus-added"
,
combobox
,
G_CALLBACK
(
savedstatus_added_cb
),
combobox
);
purple_signal_connect
(
purple_savedstatuses_get_handle
(),
"savedstatus-deleted"
,
combobox
,
G_CALLBACK
(
savedstatus_deleted_cb
),
combobox
);
purple_signal_connect
(
purple_savedstatuses_get_handle
(),
"savedstatus-modified"
,
combobox
,
G_CALLBACK
(
savedstatus_modified_cb
),
combobox
);
g_signal_connect
(
G_OBJECT
(
combobox
),
"destroy"
,
G_CALLBACK
(
purple_signals_disconnect_by_handle
),
NULL
);
return
combobox
;
}