grim/pidgin
Clone
Summary
Browse
Changes
Graph
Add a note about the DigitalOcean Sponsorship to the readme
draft
do-referral
tip
11 months ago, Gary Kramlich
2954a8b77025
Add a note about the DigitalOcean Sponsorship to the readme
/*
* Pidgin - Internet Messenger
* Copyright (C) Pidgin Developers <devel@pidgin.im>
*
* 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, see <https://www.gnu.org/licenses/>.
*/
#include
<glib/gi18n-lib.h>
#include
<adwaita.h>
#include
"pidgindisplaywindow.h"
#include
"gtkconv.h"
#include
"gtkdialogs.h"
#include
"gtkutils.h"
#include
"pidgindisplayitem.h"
#include
"pidgininvitedialog.h"
enum
{
SIG_CONVERSATION_SWITCHED
,
N_SIGNALS
,
};
static
guint
signals
[
N_SIGNALS
]
=
{
0
,
};
struct
_PidginDisplayWindow
{
GtkApplicationWindow
parent
;
GtkWidget
*
view
;
GtkWidget
*
bin
;
GListModel
*
base_model
;
GListModel
*
selection_model
;
GListStore
*
conversation_model
;
};
G_DEFINE_TYPE
(
PidginDisplayWindow
,
pidgin_display_window
,
GTK_TYPE_APPLICATION_WINDOW
)
static
GtkWidget
*
default_window
=
NULL
;
/******************************************************************************
* Helpers
*****************************************************************************/
static
void
pidgin_display_window_actions_set_enabled
(
GActionMap
*
map
,
const
gchar
**
actions
,
gboolean
enabled
)
{
for
(
int
i
=
0
;
actions
[
i
]
!=
NULL
;
i
++
)
{
GAction
*
action
=
NULL
;
const
gchar
*
name
=
actions
[
i
];
action
=
g_action_map_lookup_action
(
map
,
name
);
if
(
action
!=
NULL
)
{
g_simple_action_set_enabled
(
G_SIMPLE_ACTION
(
action
),
enabled
);
}
}
}
static
GListModel
*
pidgin_display_window_create_model
(
GObject
*
item
,
G_GNUC_UNUSED
gpointer
data
)
{
GListModel
*
model
=
NULL
;
model
=
pidgin_display_item_get_children
(
PIDGIN_DISPLAY_ITEM
(
item
));
if
(
model
!=
NULL
)
{
return
g_object_ref
(
model
);
}
return
NULL
;
}
static
gboolean
pidgin_display_window_find_conversation
(
gconstpointer
a
,
gconstpointer
b
)
{
PidginDisplayItem
*
item_a
=
PIDGIN_DISPLAY_ITEM
((
gpointer
)
a
);
PidginDisplayItem
*
item_b
=
PIDGIN_DISPLAY_ITEM
((
gpointer
)
b
);
PurpleConversation
*
conversation_a
=
NULL
;
PurpleConversation
*
conversation_b
=
NULL
;
conversation_a
=
g_object_get_data
(
G_OBJECT
(
item_a
),
"conversation"
);
conversation_b
=
g_object_get_data
(
G_OBJECT
(
item_b
),
"conversation"
);
return
(
conversation_a
==
conversation_b
);
}
/******************************************************************************
* Callbacks
*****************************************************************************/
static
void
pidgin_display_window_invite_cb
(
GtkDialog
*
dialog
,
gint
response_id
,
G_GNUC_UNUSED
gpointer
data
)
{
PidginInviteDialog
*
invite_dialog
=
PIDGIN_INVITE_DIALOG
(
dialog
);
PurpleChatConversation
*
chat
=
NULL
;
chat
=
pidgin_invite_dialog_get_conversation
(
invite_dialog
);
g_object_set_data
(
G_OBJECT
(
chat
),
"pidgin-invite-dialog"
,
NULL
);
if
(
response_id
==
GTK_RESPONSE_ACCEPT
)
{
const
gchar
*
contact
=
NULL
,
*
message
=
NULL
;
contact
=
pidgin_invite_dialog_get_contact
(
invite_dialog
);
message
=
pidgin_invite_dialog_get_message
(
invite_dialog
);
if
(
!
purple_strequal
(
contact
,
""
))
{
PurpleConnection
*
connection
=
NULL
;
connection
=
purple_conversation_get_connection
(
PURPLE_CONVERSATION
(
chat
));
purple_serv_chat_invite
(
connection
,
purple_chat_conversation_get_id
(
chat
),
message
,
contact
);
}
}
gtk_window_destroy
(
GTK_WINDOW
(
invite_dialog
));
}
/******************************************************************************
* Actions
*****************************************************************************/
static
void
pidgin_display_window_alias
(
G_GNUC_UNUSED
GSimpleAction
*
simple
,
G_GNUC_UNUSED
GVariant
*
parameter
,
gpointer
data
)
{
PidginDisplayWindow
*
window
=
data
;
PurpleConversation
*
selected
=
NULL
;
selected
=
pidgin_display_window_get_selected
(
window
);
if
(
PURPLE_IS_CONVERSATION
(
selected
))
{
PurpleAccount
*
account
;
const
gchar
*
name
;
account
=
purple_conversation_get_account
(
selected
);
name
=
purple_conversation_get_name
(
selected
);
if
(
PURPLE_IS_IM_CONVERSATION
(
selected
))
{
PurpleBuddy
*
buddy
=
purple_blist_find_buddy
(
account
,
name
);
if
(
PURPLE_IS_BUDDY
(
buddy
))
{
pidgin_dialogs_alias_buddy
(
buddy
);
}
}
else
if
(
PURPLE_IS_CHAT_CONVERSATION
(
selected
))
{
PurpleChat
*
chat
=
purple_blist_find_chat
(
account
,
name
);
if
(
PURPLE_IS_CHAT
(
chat
))
{
pidgin_dialogs_alias_chat
(
chat
);
}
}
}
}
static
void
pidgin_display_window_close_conversation
(
G_GNUC_UNUSED
GSimpleAction
*
simple
,
G_GNUC_UNUSED
GVariant
*
parameter
,
gpointer
data
)
{
PidginDisplayWindow
*
window
=
data
;
PurpleConversation
*
selected
=
NULL
;
selected
=
pidgin_display_window_get_selected
(
window
);
if
(
PURPLE_IS_CONVERSATION
(
selected
))
{
pidgin_display_window_remove
(
window
,
selected
);
pidgin_conversation_detach
(
selected
);
}
}
static
void
pidgin_display_window_get_info
(
G_GNUC_UNUSED
GSimpleAction
*
simple
,
G_GNUC_UNUSED
GVariant
*
parameter
,
gpointer
data
)
{
PidginDisplayWindow
*
window
=
data
;
PurpleConversation
*
selected
=
NULL
;
selected
=
pidgin_display_window_get_selected
(
window
);
if
(
PURPLE_IS_CONVERSATION
(
selected
))
{
if
(
PURPLE_IS_IM_CONVERSATION
(
selected
))
{
PurpleConnection
*
connection
=
NULL
;
connection
=
purple_conversation_get_connection
(
selected
);
pidgin_retrieve_user_info
(
connection
,
purple_conversation_get_name
(
selected
));
}
}
}
static
void
pidgin_display_window_invite
(
G_GNUC_UNUSED
GSimpleAction
*
simple
,
G_GNUC_UNUSED
GVariant
*
parameter
,
gpointer
data
)
{
PidginDisplayWindow
*
window
=
data
;
PurpleConversation
*
selected
=
NULL
;
selected
=
pidgin_display_window_get_selected
(
window
);
if
(
PURPLE_IS_CHAT_CONVERSATION
(
selected
))
{
GtkWidget
*
invite_dialog
=
NULL
;
invite_dialog
=
g_object_get_data
(
G_OBJECT
(
selected
),
"pidgin-invite-dialog"
);
if
(
!
GTK_IS_WIDGET
(
invite_dialog
))
{
invite_dialog
=
pidgin_invite_dialog_new
(
PURPLE_CHAT_CONVERSATION
(
selected
));
g_object_set_data
(
G_OBJECT
(
selected
),
"pidgin-invite-dialog"
,
invite_dialog
);
gtk_window_set_transient_for
(
GTK_WINDOW
(
invite_dialog
),
GTK_WINDOW
(
window
));
gtk_window_set_destroy_with_parent
(
GTK_WINDOW
(
invite_dialog
),
TRUE
);
g_signal_connect
(
invite_dialog
,
"response"
,
G_CALLBACK
(
pidgin_display_window_invite_cb
),
NULL
);
}
gtk_widget_set_visible
(
invite_dialog
,
TRUE
);
}
}
static
void
pidgin_display_window_send_file
(
G_GNUC_UNUSED
GSimpleAction
*
simple
,
G_GNUC_UNUSED
GVariant
*
parameter
,
gpointer
data
)
{
PidginDisplayWindow
*
window
=
data
;
PurpleConversation
*
selected
=
NULL
;
selected
=
pidgin_display_window_get_selected
(
window
);
if
(
PURPLE_IS_IM_CONVERSATION
(
selected
))
{
PurpleConnection
*
connection
=
NULL
;
connection
=
purple_conversation_get_connection
(
selected
);
purple_serv_send_file
(
connection
,
purple_conversation_get_name
(
selected
),
NULL
);
}
}
static
GActionEntry
win_entries
[]
=
{
{
.
name
=
"alias"
,
.
activate
=
pidgin_display_window_alias
},
{
.
name
=
"close"
,
.
activate
=
pidgin_display_window_close_conversation
},
{
.
name
=
"get-info"
,
.
activate
=
pidgin_display_window_get_info
},
{
.
name
=
"invite"
,
.
activate
=
pidgin_display_window_invite
},
{
.
name
=
"send-file"
,
.
activate
=
pidgin_display_window_send_file
}
};
/*<private>
* pidgin_display_window_conversation_actions:
*
* A list of action names that are only valid if a conversation is selected.
*/
static
const
gchar
*
pidgin_display_window_conversation_actions
[]
=
{
"alias"
,
"close"
,
"get-info"
,
NULL
};
static
const
gchar
*
pidgin_display_window_im_conversation_actions
[]
=
{
"send-file"
,
NULL
};
static
const
gchar
*
pidgin_display_window_chat_conversation_actions
[]
=
{
"invite"
,
NULL
};
/******************************************************************************
* Callbacks
*****************************************************************************/
static
gboolean
pidgin_display_window_key_pressed_cb
(
G_GNUC_UNUSED
GtkEventControllerKey
*
controller
,
guint
keyval
,
G_GNUC_UNUSED
guint
keycode
,
GdkModifierType
state
,
gpointer
data
)
{
PidginDisplayWindow
*
window
=
data
;
if
(
state
&
GDK_CONTROL_MASK
)
{
switch
(
keyval
)
{
case
GDK_KEY_Page_Down
:
case
GDK_KEY_KP_Page_Down
:
case
']'
:
pidgin_display_window_select_next
(
window
);
return
TRUE
;
break
;
case
GDK_KEY_Home
:
pidgin_display_window_select_first
(
window
);
return
TRUE
;
break
;
case
GDK_KEY_End
:
pidgin_display_window_select_last
(
window
);
return
TRUE
;
break
;
case
GDK_KEY_Page_Up
:
case
GDK_KEY_KP_Page_Up
:
case
'['
:
pidgin_display_window_select_previous
(
window
);
return
TRUE
;
break
;
}
}
else
if
(
state
&
GDK_ALT_MASK
)
{
if
(
'1'
<=
keyval
&&
keyval
<=
'9'
)
{
guint
switchto
=
keyval
-
'1'
;
pidgin_display_window_select_nth
(
window
,
switchto
);
return
TRUE
;
}
}
return
FALSE
;
}
static
void
pidgin_display_window_selected_item_changed_cb
(
GObject
*
self
,
G_GNUC_UNUSED
GParamSpec
*
pspec
,
gpointer
data
)
{
PidginDisplayItem
*
item
=
NULL
;
PidginDisplayWindow
*
window
=
data
;
PurpleConversation
*
conversation
=
NULL
;
GtkSingleSelection
*
selection
=
GTK_SINGLE_SELECTION
(
self
);
GtkTreeListRow
*
row
=
NULL
;
GtkWidget
*
widget
=
NULL
;
gboolean
is_conversation
=
FALSE
;
gboolean
is_im_conversation
=
FALSE
;
gboolean
is_chat_conversation
=
FALSE
;
row
=
gtk_single_selection_get_selected_item
(
selection
);
item
=
gtk_tree_list_row_get_item
(
row
);
/* Toggle whether actions should be enabled or disabled. */
conversation
=
g_object_get_data
(
G_OBJECT
(
item
),
"conversation"
);
if
(
PURPLE_IS_CONVERSATION
(
conversation
))
{
is_conversation
=
PURPLE_IS_CONVERSATION
(
conversation
);
is_im_conversation
=
PURPLE_IS_IM_CONVERSATION
(
conversation
);
is_chat_conversation
=
PURPLE_IS_CHAT_CONVERSATION
(
conversation
);
}
pidgin_display_window_actions_set_enabled
(
G_ACTION_MAP
(
window
),
pidgin_display_window_conversation_actions
,
is_conversation
);
pidgin_display_window_actions_set_enabled
(
G_ACTION_MAP
(
window
),
pidgin_display_window_im_conversation_actions
,
is_im_conversation
);
pidgin_display_window_actions_set_enabled
(
G_ACTION_MAP
(
window
),
pidgin_display_window_chat_conversation_actions
,
is_chat_conversation
);
widget
=
pidgin_display_item_get_widget
(
item
);
if
(
GTK_IS_WIDGET
(
widget
))
{
adw_bin_set_child
(
ADW_BIN
(
window
->
bin
),
widget
);
}
}
/******************************************************************************
* GObject Implementation
*****************************************************************************/
static
void
pidgin_display_window_finalize
(
GObject
*
obj
)
{
PidginDisplayWindow
*
window
=
PIDGIN_DISPLAY_WINDOW
(
obj
);
g_clear_object
(
&
window
->
conversation_model
);
g_clear_object
(
&
window
->
selection_model
);
G_OBJECT_CLASS
(
pidgin_display_window_parent_class
)
->
finalize
(
obj
);
}
static
void
pidgin_display_window_init
(
PidginDisplayWindow
*
window
)
{
GtkEventController
*
key
=
NULL
;
GtkTreeListModel
*
tree_model
=
NULL
;
gtk_widget_init_template
(
GTK_WIDGET
(
window
));
/* Add a reference to the selection model as we use it internally and with
* out it we get some weird call backs being called when it's nulled out
* during destruction.
*/
g_object_ref
(
window
->
selection_model
);
/* Setup the tree list model. */
tree_model
=
gtk_tree_list_model_new
(
window
->
base_model
,
FALSE
,
TRUE
,
(
GtkTreeListModelCreateModelFunc
)
pidgin_display_window_create_model
,
window
,
NULL
);
/* Set the model of the selection to the tree model. */
gtk_single_selection_set_model
(
GTK_SINGLE_SELECTION
(
window
->
selection_model
),
G_LIST_MODEL
(
tree_model
));
g_clear_object
(
&
tree_model
);
/* Set the application and add all of our actions. */
gtk_window_set_application
(
GTK_WINDOW
(
window
),
GTK_APPLICATION
(
g_application_get_default
()));
g_action_map_add_action_entries
(
G_ACTION_MAP
(
window
),
win_entries
,
G_N_ELEMENTS
(
win_entries
),
window
);
/* Add a key controller. */
key
=
gtk_event_controller_key_new
();
gtk_event_controller_set_propagation_phase
(
key
,
GTK_PHASE_CAPTURE
);
g_signal_connect
(
G_OBJECT
(
key
),
"key-pressed"
,
G_CALLBACK
(
pidgin_display_window_key_pressed_cb
),
window
);
gtk_widget_add_controller
(
GTK_WIDGET
(
window
),
key
);
}
static
void
pidgin_display_window_class_init
(
PidginDisplayWindowClass
*
klass
)
{
GObjectClass
*
obj_class
=
G_OBJECT_CLASS
(
klass
);
GtkWidgetClass
*
widget_class
=
GTK_WIDGET_CLASS
(
klass
);
obj_class
->
finalize
=
pidgin_display_window_finalize
;
/**
* PidginDisplayWindow::conversation-switched:
* @window: The conversation window.
* @new_conv: The now active conversation.
*
* Emitted when a window switched from one conversation to another.
*/
signals
[
SIG_CONVERSATION_SWITCHED
]
=
g_signal_new_class_handler
(
"conversation-switched"
,
G_OBJECT_CLASS_TYPE
(
obj_class
),
G_SIGNAL_RUN_LAST
,
NULL
,
NULL
,
NULL
,
NULL
,
G_TYPE_NONE
,
1
,
PURPLE_TYPE_CONVERSATION
);
gtk_widget_class_set_template_from_resource
(
widget_class
,
"/im/pidgin/Pidgin3/Display/window.ui"
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginDisplayWindow
,
view
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginDisplayWindow
,
bin
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginDisplayWindow
,
base_model
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginDisplayWindow
,
selection_model
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginDisplayWindow
,
conversation_model
);
gtk_widget_class_bind_template_callback
(
widget_class
,
pidgin_display_window_key_pressed_cb
);
gtk_widget_class_bind_template_callback
(
widget_class
,
pidgin_display_window_selected_item_changed_cb
);
}
/******************************************************************************
* API
*****************************************************************************/
GtkWidget
*
pidgin_display_window_get_default
(
void
)
{
if
(
!
GTK_IS_WIDGET
(
default_window
))
{
default_window
=
pidgin_display_window_new
();
g_object_add_weak_pointer
(
G_OBJECT
(
default_window
),
(
gpointer
)
&
default_window
);
}
return
default_window
;
}
GtkWidget
*
pidgin_display_window_new
(
void
)
{
return
g_object_new
(
PIDGIN_TYPE_DISPLAY_WINDOW
,
"show-menubar"
,
TRUE
,
NULL
);
}
void
pidgin_display_window_add
(
PidginDisplayWindow
*
window
,
PurpleConversation
*
conversation
)
{
PidginConversation
*
gtkconv
=
NULL
;
g_return_if_fail
(
PIDGIN_IS_DISPLAY_WINDOW
(
window
));
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
gtkconv
=
PIDGIN_CONVERSATION
(
conversation
);
if
(
gtkconv
!=
NULL
)
{
PidginDisplayItem
*
item
=
NULL
;
const
char
*
value
=
NULL
;
GtkWidget
*
parent
=
gtk_widget_get_parent
(
gtkconv
->
tab_cont
);
if
(
GTK_IS_WIDGET
(
parent
))
{
g_object_ref
(
gtkconv
->
tab_cont
);
gtk_widget_unparent
(
gtkconv
->
tab_cont
);
}
value
=
purple_conversation_get_name
(
conversation
);
item
=
pidgin_display_item_new
(
gtkconv
->
tab_cont
,
value
);
g_object_set_data
(
G_OBJECT
(
item
),
"conversation"
,
conversation
);
g_object_bind_property
(
conversation
,
"title"
,
item
,
"title"
,
G_BINDING_BIDIRECTIONAL
|
G_BINDING_SYNC_CREATE
);
g_list_store_append
(
window
->
conversation_model
,
item
);
g_clear_object
(
&
item
);
if
(
GTK_IS_WIDGET
(
parent
))
{
g_object_unref
(
gtkconv
->
tab_cont
);
}
}
}
void
pidgin_display_window_remove
(
PidginDisplayWindow
*
window
,
PurpleConversation
*
conversation
)
{
PidginDisplayItem
*
item
=
NULL
;
guint
position
=
0
;
gboolean
found
=
FALSE
;
gchar
*
id
=
NULL
;
g_return_if_fail
(
PIDGIN_IS_DISPLAY_WINDOW
(
window
));
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
/* Create a wrapper item for our find function. */
id
=
g_uuid_string_random
();
item
=
g_object_new
(
PIDGIN_TYPE_DISPLAY_ITEM
,
"id"
,
id
,
NULL
);
g_free
(
id
);
g_object_set_data
(
G_OBJECT
(
item
),
"conversation"
,
conversation
);
found
=
g_list_store_find_with_equal_func
(
window
->
conversation_model
,
item
,
pidgin_display_window_find_conversation
,
&
position
);
g_clear_object
(
&
item
);
if
(
found
)
{
g_list_store_remove
(
window
->
conversation_model
,
position
);
}
}
guint
pidgin_display_window_get_count
(
G_GNUC_UNUSED
PidginDisplayWindow
*
window
)
{
/* TODO: This is only used by the gestures plugin and that will probably
* need some rewriting and different api for a mixed content window list
* this is now.
*/
return
0
;
}
PurpleConversation
*
pidgin_display_window_get_selected
(
PidginDisplayWindow
*
window
)
{
GtkSingleSelection
*
selection
=
NULL
;
GtkTreeListRow
*
tree_row
=
NULL
;
GObject
*
selected
=
NULL
;
g_return_val_if_fail
(
PIDGIN_IS_DISPLAY_WINDOW
(
window
),
NULL
);
selection
=
GTK_SINGLE_SELECTION
(
window
->
selection_model
);
tree_row
=
gtk_single_selection_get_selected_item
(
selection
);
selected
=
gtk_tree_list_row_get_item
(
tree_row
);
if
(
PIDGIN_IS_DISPLAY_ITEM
(
selected
))
{
return
g_object_get_data
(
selected
,
"conversation"
);
}
return
NULL
;
}
void
pidgin_display_window_select
(
PidginDisplayWindow
*
window
,
PurpleConversation
*
conversation
)
{
/* TODO: This is used by the unity and gestures plugins, but I'm really not
* sure how to make this work yet without some hard-coding or something, so
* I'm opting to stub it out for now.
*/
g_return_if_fail
(
PIDGIN_IS_DISPLAY_WINDOW
(
window
));
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
}
void
pidgin_display_window_select_previous
(
PidginDisplayWindow
*
window
)
{
GtkSingleSelection
*
selection
=
NULL
;
guint
position
=
0
;
g_return_if_fail
(
PIDGIN_IS_DISPLAY_WINDOW
(
window
));
selection
=
GTK_SINGLE_SELECTION
(
window
->
selection_model
);
position
=
gtk_single_selection_get_selected
(
selection
);
if
(
position
==
0
)
{
position
=
g_list_model_get_n_items
(
G_LIST_MODEL
(
selection
))
-
1
;
}
else
{
position
=
position
-
1
;
}
gtk_single_selection_set_selected
(
selection
,
position
);
}
void
pidgin_display_window_select_next
(
PidginDisplayWindow
*
window
)
{
GtkSingleSelection
*
selection
=
NULL
;
guint
position
=
0
;
g_return_if_fail
(
PIDGIN_IS_DISPLAY_WINDOW
(
window
));
selection
=
GTK_SINGLE_SELECTION
(
window
->
selection_model
);
position
=
gtk_single_selection_get_selected
(
selection
);
if
(
position
+
1
>=
g_list_model_get_n_items
(
G_LIST_MODEL
(
selection
)))
{
position
=
0
;
}
else
{
position
=
position
+
1
;
}
gtk_single_selection_set_selected
(
selection
,
position
);
}
void
pidgin_display_window_select_first
(
PidginDisplayWindow
*
window
)
{
GtkSingleSelection
*
selection
=
NULL
;
g_return_if_fail
(
PIDGIN_IS_DISPLAY_WINDOW
(
window
));
selection
=
GTK_SINGLE_SELECTION
(
window
->
selection_model
);
/* The selection has autoselect set to true, which won't do anything if
* this is an invalid value.
*/
gtk_single_selection_set_selected
(
selection
,
0
);
}
void
pidgin_display_window_select_last
(
PidginDisplayWindow
*
window
)
{
GtkSingleSelection
*
selection
=
NULL
;
guint
n_items
=
0
;
g_return_if_fail
(
PIDGIN_IS_DISPLAY_WINDOW
(
window
));
selection
=
GTK_SINGLE_SELECTION
(
window
->
selection_model
);
n_items
=
g_list_model_get_n_items
(
G_LIST_MODEL
(
selection
));
/* The selection has autoselect set to true, which won't do anything if
* this is an invalid value.
*/
gtk_single_selection_set_selected
(
selection
,
n_items
-
1
);
}
void
pidgin_display_window_select_nth
(
PidginDisplayWindow
*
window
,
guint
nth
)
{
GtkSingleSelection
*
selection
=
NULL
;
guint
n_items
=
0
;
g_return_if_fail
(
PIDGIN_IS_DISPLAY_WINDOW
(
window
));
selection
=
GTK_SINGLE_SELECTION
(
window
->
selection_model
);
/* The selection has autoselect set to true, but this isn't bound checking
* or something on the children models, so we verify before setting.
*/
n_items
=
g_list_model_get_n_items
(
G_LIST_MODEL
(
selection
));
if
(
nth
<
n_items
)
{
gtk_single_selection_set_selected
(
selection
,
nth
);
}
}
gboolean
pidgin_display_window_conversation_is_selected
(
PidginDisplayWindow
*
window
,
PurpleConversation
*
conversation
)
{
GtkSingleSelection
*
selection
=
NULL
;
GObject
*
selected
=
NULL
;
g_return_val_if_fail
(
PIDGIN_IS_DISPLAY_WINDOW
(
window
),
FALSE
);
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
FALSE
);
selection
=
GTK_SINGLE_SELECTION
(
window
->
selection_model
);
selected
=
gtk_single_selection_get_selected_item
(
selection
);
if
(
PIDGIN_IS_DISPLAY_ITEM
(
selected
))
{
PurpleConversation
*
selected_conversation
=
NULL
;
selected_conversation
=
g_object_get_data
(
G_OBJECT
(
selected
),
"conversation"
);
if
(
selected_conversation
!=
NULL
)
{
return
(
selected_conversation
==
conversation
);
}
}
return
FALSE
;
}