pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Add a missing errno.h for FreeBSD
2020-06-14, Gary Kramlich
ce50cc06a4e0
Add a missing errno.h for FreeBSD
/* 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
<gdk/gdkkeysyms.h>
#include
<talkatu.h>
#include
"pidgin.h"
#include
<purple.h>
#include
"pidginstock.h"
#include
"gtkblist.h"
#include
"gtknotify.h"
#include
"gtkpounce.h"
#include
"gtkutils.h"
typedef
struct
{
GtkWidget
*
window
;
int
count
;
}
PidginUserInfo
;
typedef
struct
{
PurpleAccount
*
account
;
char
*
url
;
GtkWidget
*
label
;
int
count
;
gboolean
purple_has_handle
;
}
PidginNotifyMailData
;
typedef
struct
{
PurpleAccount
*
account
;
PurplePounce
*
pounce
;
char
*
pouncee
;
}
PidginNotifyPounceData
;
typedef
struct
{
PurpleAccount
*
account
;
GtkListStore
*
model
;
GtkWidget
*
treeview
;
GtkWidget
*
window
;
gpointer
user_data
;
PurpleNotifySearchResults
*
results
;
}
PidginNotifySearchResultsData
;
typedef
struct
{
PurpleNotifySearchButton
*
button
;
PidginNotifySearchResultsData
*
data
;
}
PidginNotifySearchResultsButtonData
;
enum
{
PIDGIN_MAIL_ICON
,
PIDGIN_MAIL_TEXT
,
PIDGIN_MAIL_DATA
,
COLUMNS_PIDGIN_MAIL
};
enum
{
PIDGIN_POUNCE_ICON
,
PIDGIN_POUNCE_ALIAS
,
PIDGIN_POUNCE_EVENT
,
PIDGIN_POUNCE_TEXT
,
PIDGIN_POUNCE_DATE
,
PIDGIN_POUNCE_DATA
,
COLUMNS_PIDGIN_POUNCE
};
typedef
struct
{
/*
* This must be first so PidginNotifyDialog can masquerade as the
* dialog widget.
*/
GtkWidget
*
dialog
;
GtkWidget
*
treeview
;
GtkTreeStore
*
treemodel
;
GtkLabel
*
label
;
GtkWidget
*
open_button
;
GtkWidget
*
dismiss_button
;
GtkWidget
*
edit_button
;
int
total_count
;
gboolean
in_use
;
}
PidginNotifyDialog
;
typedef
enum
{
PIDGIN_NOTIFY_MAIL
,
PIDGIN_NOTIFY_POUNCE
,
PIDGIN_NOTIFY_TYPES
}
PidginNotifyType
;
static
PidginNotifyDialog
*
mail_dialog
=
NULL
;
static
PidginNotifyDialog
*
pounce_dialog
=
NULL
;
static
PidginNotifyDialog
*
pidgin_create_notification_dialog
(
PidginNotifyType
type
);
static
void
*
pidgin_notify_emails
(
PurpleConnection
*
gc
,
size_t
count
,
gboolean
detailed
,
const
char
**
subjects
,
const
char
**
froms
,
const
char
**
tos
,
const
char
**
urls
);
static
void
pidgin_close_notify
(
PurpleNotifyType
type
,
void
*
ui_handle
);
static
void
message_response_cb
(
GtkDialog
*
dialog
,
gint
id
,
GtkWidget
*
widget
)
{
purple_notify_close
(
PURPLE_NOTIFY_MESSAGE
,
widget
);
}
static
void
pounce_response_close
(
PidginNotifyDialog
*
dialog
)
{
GtkTreeIter
iter
;
PidginNotifyPounceData
*
pounce_data
;
while
(
gtk_tree_model_get_iter_first
(
GTK_TREE_MODEL
(
pounce_dialog
->
treemodel
),
&
iter
))
{
gtk_tree_model_get
(
GTK_TREE_MODEL
(
pounce_dialog
->
treemodel
),
&
iter
,
PIDGIN_POUNCE_DATA
,
&
pounce_data
,
-1
);
gtk_tree_store_remove
(
dialog
->
treemodel
,
&
iter
);
g_free
(
pounce_data
->
pouncee
);
g_free
(
pounce_data
);
}
gtk_widget_destroy
(
pounce_dialog
->
dialog
);
g_free
(
pounce_dialog
);
pounce_dialog
=
NULL
;
}
static
void
delete_foreach
(
GtkTreeModel
*
model
,
GtkTreePath
*
path
,
GtkTreeIter
*
iter
,
gpointer
data
)
{
PidginNotifyPounceData
*
pounce_data
;
gtk_tree_model_get
(
model
,
iter
,
PIDGIN_POUNCE_DATA
,
&
pounce_data
,
-1
);
if
(
pounce_data
!=
NULL
)
{
g_free
(
pounce_data
->
pouncee
);
g_free
(
pounce_data
);
}
}
static
void
open_im_foreach
(
GtkTreeModel
*
model
,
GtkTreePath
*
path
,
GtkTreeIter
*
iter
,
gpointer
data
)
{
PidginNotifyPounceData
*
pounce_data
;
gtk_tree_model_get
(
model
,
iter
,
PIDGIN_POUNCE_DATA
,
&
pounce_data
,
-1
);
if
(
pounce_data
!=
NULL
)
{
PurpleIMConversation
*
im
;
im
=
purple_im_conversation_new
(
pounce_data
->
account
,
pounce_data
->
pouncee
);
purple_conversation_present
(
PURPLE_CONVERSATION
(
im
));
}
}
static
void
append_to_list
(
GtkTreeModel
*
model
,
GtkTreePath
*
path
,
GtkTreeIter
*
iter
,
gpointer
data
)
{
GList
**
list
=
data
;
*
list
=
g_list_prepend
(
*
list
,
gtk_tree_path_copy
(
path
));
}
static
void
pounce_response_dismiss
()
{
GtkTreeModel
*
model
=
GTK_TREE_MODEL
(
pounce_dialog
->
treemodel
);
GtkTreeSelection
*
selection
;
GtkTreeIter
iter
;
GtkTreeIter
new_selection
;
GList
*
list
=
NULL
;
gboolean
found_selection
=
FALSE
;
selection
=
gtk_tree_view_get_selection
(
GTK_TREE_VIEW
(
pounce_dialog
->
treeview
));
gtk_tree_selection_selected_foreach
(
selection
,
delete_foreach
,
pounce_dialog
);
gtk_tree_selection_selected_foreach
(
selection
,
append_to_list
,
&
list
);
g_return_if_fail
(
list
!=
NULL
);
if
(
list
->
next
==
NULL
)
{
gtk_tree_model_get_iter
(
model
,
&
new_selection
,
list
->
data
);
if
(
gtk_tree_model_iter_next
(
model
,
&
new_selection
))
found_selection
=
TRUE
;
else
{
/* This is the last thing in the list */
GtkTreePath
*
path
;
/* Because gtk_tree_model_iter_prev doesn't exist... */
gtk_tree_model_get_iter
(
model
,
&
new_selection
,
list
->
data
);
path
=
gtk_tree_model_get_path
(
model
,
&
new_selection
);
if
(
gtk_tree_path_prev
(
path
))
{
gtk_tree_model_get_iter
(
model
,
&
new_selection
,
path
);
found_selection
=
TRUE
;
}
gtk_tree_path_free
(
path
);
}
}
while
(
list
)
{
if
(
gtk_tree_model_get_iter
(
model
,
&
iter
,
list
->
data
))
{
gtk_tree_store_remove
(
GTK_TREE_STORE
(
pounce_dialog
->
treemodel
),
&
iter
);
}
gtk_tree_path_free
(
list
->
data
);
list
=
g_list_delete_link
(
list
,
list
);
}
if
(
gtk_tree_model_get_iter_first
(
model
,
&
iter
))
{
if
(
found_selection
)
gtk_tree_selection_select_iter
(
selection
,
&
new_selection
);
else
gtk_tree_selection_select_iter
(
selection
,
&
iter
);
}
else
pounce_response_close
(
pounce_dialog
);
}
static
void
pounce_response_open_ims
()
{
GtkTreeSelection
*
selection
;
selection
=
gtk_tree_view_get_selection
(
GTK_TREE_VIEW
(
pounce_dialog
->
treeview
));
gtk_tree_selection_selected_foreach
(
selection
,
open_im_foreach
,
pounce_dialog
);
pounce_response_dismiss
();
}
static
void
pounce_response_edit_cb
(
GtkTreeModel
*
model
,
GtkTreePath
*
path
,
GtkTreeIter
*
iter
,
gpointer
data
)
{
PidginNotifyPounceData
*
pounce_data
;
PidginNotifyDialog
*
dialog
=
(
PidginNotifyDialog
*
)
data
;
GList
*
list
;
list
=
purple_pounces_get_all
();
gtk_tree_model_get
(
GTK_TREE_MODEL
(
dialog
->
treemodel
),
iter
,
PIDGIN_POUNCE_DATA
,
&
pounce_data
,
-1
);
if
(
g_list_find
(
list
,
pounce_data
->
pounce
)
!=
NULL
)
{
pidgin_pounce_editor_show
(
pounce_data
->
account
,
NULL
,
pounce_data
->
pounce
);
return
;
}
purple_debug_warning
(
"gtknotify"
,
"Pounce was destroyed.
\n
"
);
}
static
void
pounce_response_cb
(
GtkDialog
*
dlg
,
gint
id
,
PidginNotifyDialog
*
dialog
)
{
GtkTreeSelection
*
selection
=
NULL
;
switch
(
id
)
{
case
GTK_RESPONSE_CLOSE
:
case
GTK_RESPONSE_DELETE_EVENT
:
pounce_response_close
(
dialog
);
break
;
case
GTK_RESPONSE_YES
:
pounce_response_open_ims
();
break
;
case
GTK_RESPONSE_NO
:
pounce_response_dismiss
();
break
;
case
GTK_RESPONSE_APPLY
:
selection
=
gtk_tree_view_get_selection
(
GTK_TREE_VIEW
(
dialog
->
treeview
));
gtk_tree_selection_selected_foreach
(
selection
,
pounce_response_edit_cb
,
dialog
);
break
;
}
}
static
void
pounce_row_selected_cb
(
GtkTreeView
*
tv
,
GtkTreePath
*
path
,
GtkTreeViewColumn
*
col
,
gpointer
data
)
{
GtkTreeSelection
*
selection
;
int
count
;
selection
=
gtk_tree_view_get_selection
(
GTK_TREE_VIEW
(
pounce_dialog
->
treeview
));
count
=
gtk_tree_selection_count_selected_rows
(
selection
);
if
(
count
==
0
)
{
gtk_widget_set_sensitive
(
pounce_dialog
->
open_button
,
FALSE
);
gtk_widget_set_sensitive
(
pounce_dialog
->
edit_button
,
FALSE
);
gtk_widget_set_sensitive
(
pounce_dialog
->
dismiss_button
,
FALSE
);
}
else
if
(
count
==
1
)
{
GList
*
pounces
;
GList
*
list
;
PidginNotifyPounceData
*
pounce_data
;
GtkTreeIter
iter
;
list
=
gtk_tree_selection_get_selected_rows
(
selection
,
NULL
);
gtk_tree_model_get_iter
(
GTK_TREE_MODEL
(
pounce_dialog
->
treemodel
),
&
iter
,
list
->
data
);
gtk_tree_model_get
(
GTK_TREE_MODEL
(
pounce_dialog
->
treemodel
),
&
iter
,
PIDGIN_POUNCE_DATA
,
&
pounce_data
,
-1
);
g_list_free_full
(
list
,
(
GDestroyNotify
)
gtk_tree_path_free
);
pounces
=
purple_pounces_get_all
();
if
(
g_list_find
(
pounces
,
pounce_data
->
pounce
)
!=
NULL
)
{
gtk_widget_set_sensitive
(
pounce_dialog
->
edit_button
,
TRUE
);
}
gtk_widget_set_sensitive
(
pounce_dialog
->
open_button
,
TRUE
);
gtk_widget_set_sensitive
(
pounce_dialog
->
dismiss_button
,
TRUE
);
}
else
{
gtk_widget_set_sensitive
(
pounce_dialog
->
open_button
,
TRUE
);
gtk_widget_set_sensitive
(
pounce_dialog
->
edit_button
,
FALSE
);
gtk_widget_set_sensitive
(
pounce_dialog
->
dismiss_button
,
TRUE
);
}
}
static
void
reset_mail_dialog
(
gpointer
unused
)
{
g_return_if_fail
(
mail_dialog
!=
NULL
);
if
(
mail_dialog
->
in_use
)
return
;
gtk_widget_destroy
(
mail_dialog
->
dialog
);
g_free
(
mail_dialog
);
mail_dialog
=
NULL
;
purple_signal_emit
(
purple_notify_get_handle
(),
"displaying-emails-clear"
);
}
gboolean
pidgin_notify_emails_pending
()
{
return
mail_dialog
!=
NULL
&&
!
gtk_widget_get_visible
(
mail_dialog
->
dialog
);
}
void
pidgin_notify_emails_present
(
void
*
data
)
{
if
(
pidgin_notify_emails_pending
())
{
gtk_widget_show_all
(
mail_dialog
->
dialog
);
mail_dialog
->
in_use
=
TRUE
;
pidgin_blist_set_headline
(
NULL
,
NULL
,
NULL
,
NULL
,
NULL
);
mail_dialog
->
in_use
=
FALSE
;
}
purple_signal_emit
(
purple_notify_get_handle
(),
"displaying-emails-clear"
);
}
static
void
email_response_cb
(
GtkDialog
*
unused
,
gint
id
,
PidginNotifyDialog
*
unused2
)
{
PidginNotifyMailData
*
data
=
NULL
;
GtkTreeModel
*
model
=
GTK_TREE_MODEL
(
mail_dialog
->
treemodel
);
GtkTreeIter
iter
;
if
(
id
==
GTK_RESPONSE_YES
)
{
/* A single row activated. Remove that row. */
GtkTreeSelection
*
selection
;
selection
=
gtk_tree_view_get_selection
(
GTK_TREE_VIEW
(
mail_dialog
->
treeview
));
if
(
gtk_tree_selection_get_selected
(
selection
,
NULL
,
&
iter
))
{
gtk_tree_model_get
(
model
,
&
iter
,
PIDGIN_MAIL_DATA
,
&
data
,
-1
);
purple_notify_uri
(
NULL
,
data
->
url
);
gtk_tree_store_remove
(
mail_dialog
->
treemodel
,
&
iter
);
if
(
data
->
purple_has_handle
)
purple_notify_close
(
PURPLE_NOTIFY_EMAILS
,
data
);
else
pidgin_close_notify
(
PURPLE_NOTIFY_EMAILS
,
data
);
if
(
gtk_tree_model_get_iter_first
(
model
,
&
iter
))
return
;
}
else
return
;
}
else
{
/* Remove all the rows */
while
(
gtk_tree_model_get_iter_first
(
model
,
&
iter
))
{
gtk_tree_model_get
(
model
,
&
iter
,
PIDGIN_MAIL_DATA
,
&
data
,
-1
);
if
(
id
==
GTK_RESPONSE_ACCEPT
)
purple_notify_uri
(
NULL
,
data
->
url
);
gtk_tree_store_remove
(
mail_dialog
->
treemodel
,
&
iter
);
if
(
data
->
purple_has_handle
)
purple_notify_close
(
PURPLE_NOTIFY_EMAILS
,
data
);
else
pidgin_close_notify
(
PURPLE_NOTIFY_EMAILS
,
data
);
}
}
reset_mail_dialog
(
NULL
);
}
static
void
email_row_activated_cb
(
GtkTreeView
*
tv
,
GtkTreePath
*
path
,
GtkTreeViewColumn
*
col
,
gpointer
data
)
{
email_response_cb
(
NULL
,
GTK_RESPONSE_YES
,
NULL
);
}
static
gboolean
formatted_close_cb
(
GtkWidget
*
win
,
GdkEvent
*
event
,
void
*
user_data
)
{
purple_notify_close
(
PURPLE_NOTIFY_FORMATTED
,
win
);
return
FALSE
;
}
static
gboolean
searchresults_close_cb
(
PidginNotifySearchResultsData
*
data
,
GdkEvent
*
event
,
gpointer
user_data
)
{
purple_notify_close
(
PURPLE_NOTIFY_SEARCHRESULTS
,
data
);
return
FALSE
;
}
static
void
searchresults_callback_wrapper_cb
(
GtkWidget
*
widget
,
PidginNotifySearchResultsButtonData
*
bd
)
{
PidginNotifySearchResultsData
*
data
=
bd
->
data
;
GtkTreeSelection
*
selection
;
GtkTreeModel
*
model
;
GtkTreeIter
iter
;
PurpleNotifySearchButton
*
button
;
GList
*
row
=
NULL
;
gchar
*
str
;
int
i
;
g_return_if_fail
(
data
!=
NULL
);
selection
=
gtk_tree_view_get_selection
(
GTK_TREE_VIEW
(
data
->
treeview
));
if
(
gtk_tree_selection_get_selected
(
selection
,
&
model
,
&
iter
))
{
for
(
i
=
1
;
i
<
gtk_tree_model_get_n_columns
(
GTK_TREE_MODEL
(
model
));
i
++
)
{
gtk_tree_model_get
(
GTK_TREE_MODEL
(
model
),
&
iter
,
i
,
&
str
,
-1
);
row
=
g_list_append
(
row
,
str
);
}
}
button
=
bd
->
button
;
button
->
callback
(
purple_account_get_connection
(
data
->
account
),
row
,
data
->
user_data
);
g_list_free_full
(
row
,
g_free
);
}
/* copy-paste from gtkrequest.c */
static
void
pidgin_widget_decorate_account
(
GtkWidget
*
cont
,
PurpleAccount
*
account
)
{
GtkWidget
*
image
;
GdkPixbuf
*
pixbuf
;
if
(
!
account
)
return
;
pixbuf
=
pidgin_create_protocol_icon
(
account
,
PIDGIN_PROTOCOL_ICON_SMALL
);
image
=
gtk_image_new_from_pixbuf
(
pixbuf
);
g_object_unref
(
G_OBJECT
(
pixbuf
));
gtk_widget_set_tooltip_text
(
image
,
purple_account_get_username
(
account
));
if
(
GTK_IS_BOX
(
cont
))
{
gtk_widget_set_halign
(
image
,
GTK_ALIGN_START
);
gtk_widget_set_valign
(
image
,
GTK_ALIGN_START
);
gtk_box_pack_end
(
GTK_BOX
(
cont
),
image
,
FALSE
,
TRUE
,
0
);
}
gtk_widget_show
(
image
);
}
static
void
*
pidgin_notify_message
(
PurpleNotifyMessageType
type
,
const
char
*
title
,
const
char
*
primary
,
const
char
*
secondary
,
PurpleRequestCommonParameters
*
cpar
)
{
GtkWidget
*
dialog
;
GtkWidget
*
hbox
;
GtkWidget
*
label
;
GtkWidget
*
img
=
NULL
;
char
label_text
[
2048
];
const
char
*
icon_name
=
NULL
;
char
*
primary_esc
,
*
secondary_esc
;
switch
(
type
)
{
case
PURPLE_NOTIFY_MSG_ERROR
:
icon_name
=
"dialog-error"
;
break
;
case
PURPLE_NOTIFY_MSG_WARNING
:
icon_name
=
"dialog-warning"
;
break
;
case
PURPLE_NOTIFY_MSG_INFO
:
icon_name
=
"dialog-information"
;
break
;
default
:
icon_name
=
NULL
;
break
;
}
if
(
icon_name
!=
NULL
)
{
img
=
gtk_image_new_from_icon_name
(
icon_name
,
GTK_ICON_SIZE_DIALOG
);
gtk_widget_set_halign
(
img
,
GTK_ALIGN_START
);
gtk_widget_set_valign
(
img
,
GTK_ALIGN_START
);
}
dialog
=
gtk_dialog_new_with_buttons
(
title
?
title
:
PIDGIN_ALERT_TITLE
,
NULL
,
0
,
GTK_STOCK_CLOSE
,
GTK_RESPONSE_CLOSE
,
NULL
);
gtk_window_set_role
(
GTK_WINDOW
(
dialog
),
"notify_dialog"
);
g_signal_connect
(
G_OBJECT
(
dialog
),
"response"
,
G_CALLBACK
(
message_response_cb
),
dialog
);
gtk_container_set_border_width
(
GTK_CONTAINER
(
dialog
),
PIDGIN_HIG_BORDER
);
gtk_window_set_resizable
(
GTK_WINDOW
(
dialog
),
FALSE
);
gtk_box_set_spacing
(
GTK_BOX
(
gtk_dialog_get_content_area
(
GTK_DIALOG
(
dialog
))),
PIDGIN_HIG_BORDER
);
gtk_container_set_border_width
(
GTK_CONTAINER
(
gtk_dialog_get_content_area
(
GTK_DIALOG
(
dialog
))),
PIDGIN_HIG_BOX_SPACE
);
hbox
=
gtk_box_new
(
GTK_ORIENTATION_HORIZONTAL
,
PIDGIN_HIG_BORDER
);
gtk_container_add
(
GTK_CONTAINER
(
gtk_dialog_get_content_area
(
GTK_DIALOG
(
dialog
))),
hbox
);
if
(
img
!=
NULL
)
gtk_box_pack_start
(
GTK_BOX
(
hbox
),
img
,
FALSE
,
FALSE
,
0
);
pidgin_widget_decorate_account
(
hbox
,
purple_request_cpar_get_account
(
cpar
));
primary_esc
=
g_markup_escape_text
(
primary
,
-1
);
secondary_esc
=
(
secondary
!=
NULL
)
?
g_markup_escape_text
(
secondary
,
-1
)
:
NULL
;
g_snprintf
(
label_text
,
sizeof
(
label_text
),
"<span weight=
\"
bold
\"
size=
\"
larger
\"
>%s</span>%s%s"
,
primary_esc
,
(
secondary
?
"
\n\n
"
:
""
),
(
secondary
?
secondary_esc
:
""
));
g_free
(
primary_esc
);
g_free
(
secondary_esc
);
label
=
gtk_label_new
(
NULL
);
gtk_label_set_markup
(
GTK_LABEL
(
label
),
label_text
);
gtk_label_set_line_wrap
(
GTK_LABEL
(
label
),
TRUE
);
gtk_label_set_selectable
(
GTK_LABEL
(
label
),
TRUE
);
gtk_label_set_xalign
(
GTK_LABEL
(
label
),
0
);
gtk_label_set_yalign
(
GTK_LABEL
(
label
),
0
);
gtk_box_pack_start
(
GTK_BOX
(
hbox
),
label
,
FALSE
,
FALSE
,
0
);
g_object_set_data
(
G_OBJECT
(
dialog
),
"pidgin-parent-from"
,
purple_request_cpar_get_parent_from
(
cpar
));
pidgin_auto_parent_window
(
dialog
);
gtk_widget_show_all
(
dialog
);
return
dialog
;
}
static
void
selection_changed_cb
(
GtkTreeSelection
*
sel
,
PidginNotifyDialog
*
dialog
)
{
GtkTreeIter
iter
;
GtkTreeModel
*
model
;
PidginNotifyMailData
*
data
;
gboolean
active
=
TRUE
;
if
(
gtk_tree_selection_get_selected
(
sel
,
&
model
,
&
iter
)
==
FALSE
)
active
=
FALSE
;
else
{
gtk_tree_model_get
(
model
,
&
iter
,
PIDGIN_MAIL_DATA
,
&
data
,
-1
);
if
(
data
->
url
==
NULL
)
active
=
FALSE
;
}
gtk_widget_set_sensitive
(
dialog
->
open_button
,
active
);
}
static
void
*
pidgin_notify_email
(
PurpleConnection
*
gc
,
const
char
*
subject
,
const
char
*
from
,
const
char
*
to
,
const
char
*
url
)
{
return
pidgin_notify_emails
(
gc
,
1
,
(
subject
!=
NULL
),
(
subject
==
NULL
?
NULL
:
&
subject
),
(
from
==
NULL
?
NULL
:
&
from
),
(
to
==
NULL
?
NULL
:
&
to
),
(
url
==
NULL
?
NULL
:
&
url
));
}
static
int
mail_window_focus_cb
(
GtkWidget
*
widget
,
GdkEventFocus
*
focus
,
gpointer
null
)
{
pidgin_set_urgent
(
GTK_WINDOW
(
widget
),
FALSE
);
return
0
;
}
/* count == 0 means this is a detailed mail notification.
* count > 0 mean non-detailed.
*/
static
void
*
pidgin_notify_add_mail
(
GtkTreeStore
*
treemodel
,
PurpleAccount
*
account
,
char
*
notification
,
const
char
*
url
,
int
count
,
gboolean
clear
,
gboolean
*
new_data
)
{
PidginNotifyMailData
*
data
=
NULL
;
GtkTreeIter
iter
;
GdkPixbuf
*
icon
;
gboolean
new_n
=
TRUE
;
if
(
count
>
0
||
clear
)
{
/* Allow only one non-detailed email notification for each account */
if
(
gtk_tree_model_get_iter_first
(
GTK_TREE_MODEL
(
treemodel
),
&
iter
))
{
gboolean
advanced
;
do
{
advanced
=
FALSE
;
gtk_tree_model_get
(
GTK_TREE_MODEL
(
treemodel
),
&
iter
,
PIDGIN_MAIL_DATA
,
&
data
,
-1
);
if
(
data
&&
data
->
account
==
account
)
{
if
(
clear
)
{
advanced
=
gtk_tree_store_remove
(
treemodel
,
&
iter
);
mail_dialog
->
total_count
-=
data
->
count
;
if
(
data
->
purple_has_handle
)
purple_notify_close
(
PURPLE_NOTIFY_EMAILS
,
data
);
else
pidgin_close_notify
(
PURPLE_NOTIFY_EMAILS
,
data
);
/* We're completely done if we've processed all entries */
if
(
!
advanced
)
return
NULL
;
}
else
if
(
data
->
count
>
0
)
{
new_n
=
FALSE
;
g_free
(
data
->
url
);
data
->
url
=
NULL
;
mail_dialog
->
total_count
-=
data
->
count
;
break
;
}
}
}
while
(
advanced
||
gtk_tree_model_iter_next
(
GTK_TREE_MODEL
(
treemodel
),
&
iter
));
}
}
if
(
clear
)
return
NULL
;
icon
=
pidgin_create_protocol_icon
(
account
,
PIDGIN_PROTOCOL_ICON_MEDIUM
);
if
(
new_n
)
{
data
=
g_new0
(
PidginNotifyMailData
,
1
);
data
->
purple_has_handle
=
TRUE
;
gtk_tree_store_append
(
treemodel
,
&
iter
,
NULL
);
}
if
(
url
!=
NULL
)
data
->
url
=
g_strdup
(
url
);
gtk_tree_store_set
(
treemodel
,
&
iter
,
PIDGIN_MAIL_ICON
,
icon
,
PIDGIN_MAIL_TEXT
,
notification
,
PIDGIN_MAIL_DATA
,
data
,
-1
);
data
->
account
=
account
;
/* count == 0 indicates we're adding a single detailed e-mail */
data
->
count
=
count
>
0
?
count
:
1
;
if
(
icon
)
g_object_unref
(
icon
);
if
(
new_data
)
*
new_data
=
new_n
;
return
data
;
}
static
void
*
pidgin_notify_emails
(
PurpleConnection
*
gc
,
size_t
count
,
gboolean
detailed
,
const
char
**
subjects
,
const
char
**
froms
,
const
char
**
tos
,
const
char
**
urls
)
{
char
*
notification
;
PurpleAccount
*
account
;
PidginNotifyMailData
*
data
=
NULL
,
*
data2
;
gboolean
new_data
=
FALSE
;
GtkTreeSelection
*
sel
;
GtkTreeIter
iter
;
/* Don't bother updating if there aren't new emails and we don't have any displayed currently */
if
(
count
==
0
&&
mail_dialog
==
NULL
)
return
NULL
;
account
=
purple_connection_get_account
(
gc
);
if
(
mail_dialog
==
NULL
)
mail_dialog
=
pidgin_create_notification_dialog
(
PIDGIN_NOTIFY_MAIL
);
mail_dialog
->
total_count
+=
count
;
if
(
detailed
)
{
for
(
;
count
;
--
count
)
{
char
*
to_text
=
NULL
;
char
*
from_text
=
NULL
;
char
*
subject_text
=
NULL
;
char
*
tmp
;
gboolean
first
=
TRUE
;
if
(
tos
!=
NULL
)
{
tmp
=
g_markup_escape_text
(
*
tos
,
-1
);
to_text
=
g_strdup_printf
(
"<b>%s</b>: %s
\n
"
,
_
(
"Account"
),
tmp
);
g_free
(
tmp
);
first
=
FALSE
;
tos
++
;
}
if
(
froms
!=
NULL
)
{
tmp
=
g_markup_escape_text
(
*
froms
,
-1
);
from_text
=
g_strdup_printf
(
"%s<b>%s</b>: %s
\n
"
,
first
?
"<br>"
:
""
,
_
(
"Sender"
),
tmp
);
g_free
(
tmp
);
first
=
FALSE
;
froms
++
;
}
if
(
subjects
!=
NULL
)
{
tmp
=
g_markup_escape_text
(
*
subjects
,
-1
);
subject_text
=
g_strdup_printf
(
"%s<b>%s</b>: %s"
,
first
?
"<br>"
:
""
,
_
(
"Subject"
),
tmp
);
g_free
(
tmp
);
first
=
FALSE
;
subjects
++
;
}
#define SAFE(x) ((x) ? (x) : "")
notification
=
g_strdup_printf
(
"%s%s%s"
,
SAFE
(
to_text
),
SAFE
(
from_text
),
SAFE
(
subject_text
));
#undef SAFE
g_free
(
to_text
);
g_free
(
from_text
);
g_free
(
subject_text
);
(
void
)
first
;
/* If we don't keep track of this, will leak "data" for each of the notifications except the last */
data2
=
pidgin_notify_add_mail
(
mail_dialog
->
treemodel
,
account
,
notification
,
urls
?
*
urls
:
NULL
,
0
,
FALSE
,
&
new_data
);
if
(
data2
&&
new_data
)
{
if
(
data
)
data
->
purple_has_handle
=
FALSE
;
data
=
data2
;
}
g_free
(
notification
);
if
(
urls
!=
NULL
)
urls
++
;
}
}
else
{
if
(
count
>
0
)
{
notification
=
g_strdup_printf
(
ngettext
(
"%s has %d new message."
,
"%s has %d new messages."
,
(
int
)
count
),
tos
?
*
tos
:
"(unknown)"
,
(
int
)
count
);
data2
=
pidgin_notify_add_mail
(
mail_dialog
->
treemodel
,
account
,
notification
,
urls
?
*
urls
:
NULL
,
count
,
FALSE
,
&
new_data
);
if
(
data2
&&
new_data
)
{
data
=
data2
;
}
g_free
(
notification
);
}
else
{
/* Clear out all mails for the account */
pidgin_notify_add_mail
(
mail_dialog
->
treemodel
,
account
,
NULL
,
NULL
,
0
,
TRUE
,
NULL
);
if
(
mail_dialog
->
total_count
==
0
)
{
/*
* There is no API to clear the headline specifically
* This will trigger reset_mail_dialog()
*/
pidgin_blist_set_headline
(
NULL
,
NULL
,
NULL
,
NULL
,
NULL
);
return
NULL
;
}
}
}
/* Select first item if nothing selected */
sel
=
gtk_tree_view_get_selection
(
GTK_TREE_VIEW
(
mail_dialog
->
treeview
));
if
((
gtk_tree_selection_count_selected_rows
(
sel
)
<
1
)
&&
gtk_tree_model_get_iter_first
(
GTK_TREE_MODEL
(
mail_dialog
->
treemodel
),
&
iter
))
{
gtk_tree_selection_select_iter
(
sel
,
&
iter
);
}
if
(
!
gtk_widget_get_visible
(
mail_dialog
->
dialog
))
{
char
*
label_text
=
g_strdup_printf
(
ngettext
(
"<b>%d new email.</b>"
,
"<b>%d new emails.</b>"
,
mail_dialog
->
total_count
),
mail_dialog
->
total_count
);
mail_dialog
->
in_use
=
TRUE
;
/* So that _set_headline doesn't accidentally
remove the notifications when replacing an
old notification. */
pidgin_blist_set_headline
(
label_text
,
"mail-unread"
,
G_CALLBACK
(
pidgin_notify_emails_present
),
mail_dialog
->
dialog
,
reset_mail_dialog
);
mail_dialog
->
in_use
=
FALSE
;
g_free
(
label_text
);
}
else
if
(
!
gtk_widget_has_focus
(
mail_dialog
->
dialog
))
pidgin_set_urgent
(
GTK_WINDOW
(
mail_dialog
->
dialog
),
TRUE
);
return
data
;
}
static
gboolean
formatted_input_cb
(
GtkWidget
*
win
,
GdkEventKey
*
event
,
gpointer
data
)
{
if
(
event
->
keyval
==
GDK_KEY_Escape
)
{
purple_notify_close
(
PURPLE_NOTIFY_FORMATTED
,
win
);
return
TRUE
;
}
return
FALSE
;
}
static
void
*
pidgin_notify_formatted
(
const
char
*
title
,
const
char
*
primary
,
const
char
*
secondary
,
const
char
*
text
)
{
GtkWidget
*
window
;
GtkWidget
*
vbox
;
GtkWidget
*
label
;
GtkWidget
*
button
;
GtkWidget
*
sw
;
GtkWidget
*
view
;
GtkTextBuffer
*
buffer
;
char
label_text
[
2048
];
char
*
linked_text
,
*
primary_esc
,
*
secondary_esc
;
window
=
gtk_dialog_new
();
gtk_window_set_title
(
GTK_WINDOW
(
window
),
title
);
gtk_window_set_resizable
(
GTK_WINDOW
(
window
),
TRUE
);
g_signal_connect
(
G_OBJECT
(
window
),
"delete_event"
,
G_CALLBACK
(
formatted_close_cb
),
NULL
);
/* Setup the main vbox */
vbox
=
gtk_dialog_get_content_area
(
GTK_DIALOG
(
window
));
/* Setup the descriptive label */
primary_esc
=
g_markup_escape_text
(
primary
,
-1
);
secondary_esc
=
(
secondary
!=
NULL
)
?
g_markup_escape_text
(
secondary
,
-1
)
:
NULL
;
g_snprintf
(
label_text
,
sizeof
(
label_text
),
"<span weight=
\"
bold
\"
size=
\"
larger
\"
>%s</span>%s%s"
,
primary_esc
,
(
secondary
?
"
\n
"
:
""
),
(
secondary
?
secondary_esc
:
""
));
g_free
(
primary_esc
);
g_free
(
secondary_esc
);
label
=
gtk_label_new
(
NULL
);
gtk_label_set_markup
(
GTK_LABEL
(
label
),
label_text
);
gtk_label_set_line_wrap
(
GTK_LABEL
(
label
),
TRUE
);
gtk_label_set_selectable
(
GTK_LABEL
(
label
),
TRUE
);
gtk_label_set_xalign
(
GTK_LABEL
(
label
),
0
);
gtk_label_set_yalign
(
GTK_LABEL
(
label
),
0
);
gtk_box_pack_start
(
GTK_BOX
(
vbox
),
label
,
FALSE
,
FALSE
,
0
);
gtk_widget_show
(
label
);
/* Add the view */
sw
=
gtk_scrolled_window_new
(
NULL
,
NULL
);
gtk_box_pack_start
(
GTK_BOX
(
vbox
),
sw
,
TRUE
,
TRUE
,
0
);
buffer
=
talkatu_html_buffer_new
();
view
=
talkatu_view_new_with_buffer
(
buffer
);
gtk_container_add
(
GTK_CONTAINER
(
sw
),
view
);
gtk_widget_set_name
(
view
,
"pidgin_notify_view"
);
gtk_widget_set_size_request
(
view
,
300
,
250
);
gtk_widget_show_all
(
sw
);
/* Add the Close button. */
button
=
gtk_dialog_add_button
(
GTK_DIALOG
(
window
),
GTK_STOCK_CLOSE
,
GTK_RESPONSE_CLOSE
);
gtk_widget_grab_focus
(
button
);
g_signal_connect_swapped
(
G_OBJECT
(
button
),
"clicked"
,
G_CALLBACK
(
formatted_close_cb
),
window
);
g_signal_connect
(
G_OBJECT
(
window
),
"key_press_event"
,
G_CALLBACK
(
formatted_input_cb
),
NULL
);
/* Make sure URLs are clickable */
linked_text
=
purple_markup_linkify
(
text
);
talkatu_markup_set_html
(
TALKATU_BUFFER
(
buffer
),
linked_text
,
-1
);
g_free
(
linked_text
);
g_object_set_data
(
G_OBJECT
(
window
),
"view-widget"
,
view
);
/* Show the window */
pidgin_auto_parent_window
(
window
);
gtk_widget_show
(
window
);
return
window
;
}
static
void
pidgin_notify_searchresults_new_rows
(
PurpleConnection
*
gc
,
PurpleNotifySearchResults
*
results
,
void
*
data_
)
{
PidginNotifySearchResultsData
*
data
=
data_
;
GtkListStore
*
model
=
data
->
model
;
GtkTreeIter
iter
;
GdkPixbuf
*
pixbuf
;
GList
*
row
,
*
column
;
guint
n
;
gtk_list_store_clear
(
data
->
model
);
pixbuf
=
pidgin_create_protocol_icon
(
purple_connection_get_account
(
gc
),
PIDGIN_PROTOCOL_ICON_SMALL
);
for
(
row
=
results
->
rows
;
row
!=
NULL
;
row
=
row
->
next
)
{
gtk_list_store_append
(
model
,
&
iter
);
gtk_list_store_set
(
model
,
&
iter
,
0
,
pixbuf
,
-1
);
n
=
1
;
for
(
column
=
row
->
data
;
column
!=
NULL
;
column
=
column
->
next
)
{
GValue
v
;
v
.
g_type
=
0
;
g_value_init
(
&
v
,
G_TYPE_STRING
);
g_value_set_string
(
&
v
,
column
->
data
);
gtk_list_store_set_value
(
model
,
&
iter
,
n
,
&
v
);
n
++
;
}
}
if
(
pixbuf
!=
NULL
)
g_object_unref
(
pixbuf
);
}
static
void
*
pidgin_notify_searchresults
(
PurpleConnection
*
gc
,
const
char
*
title
,
const
char
*
primary
,
const
char
*
secondary
,
PurpleNotifySearchResults
*
results
,
gpointer
user_data
)
{
GtkWidget
*
window
;
GtkWidget
*
treeview
;
GtkWidget
*
close_button
;
GType
*
col_types
;
GtkListStore
*
model
;
GtkCellRenderer
*
renderer
;
guint
col_num
;
GList
*
columniter
;
guint
i
;
GList
*
l
;
GtkWidget
*
vbox
;
GtkWidget
*
label
;
PidginNotifySearchResultsData
*
data
;
char
*
label_text
;
char
*
primary_esc
,
*
secondary_esc
;
g_return_val_if_fail
(
gc
!=
NULL
,
NULL
);
g_return_val_if_fail
(
results
!=
NULL
,
NULL
);
data
=
g_new0
(
PidginNotifySearchResultsData
,
1
);
data
->
user_data
=
user_data
;
data
->
results
=
results
;
/* Create the window */
window
=
gtk_dialog_new
();
gtk_window_set_title
(
GTK_WINDOW
(
window
),
title
?
title
:
_
(
"Search Results"
));
gtk_container_set_border_width
(
GTK_CONTAINER
(
window
),
PIDGIN_HIG_BORDER
);
gtk_window_set_resizable
(
GTK_WINDOW
(
window
),
TRUE
);
g_signal_connect_swapped
(
G_OBJECT
(
window
),
"delete_event"
,
G_CALLBACK
(
searchresults_close_cb
),
data
);
/* Setup the main vbox */
vbox
=
gtk_dialog_get_content_area
(
GTK_DIALOG
(
window
));
/* Setup the descriptive label */
primary_esc
=
(
primary
!=
NULL
)
?
g_markup_escape_text
(
primary
,
-1
)
:
NULL
;
secondary_esc
=
(
secondary
!=
NULL
)
?
g_markup_escape_text
(
secondary
,
-1
)
:
NULL
;
label_text
=
g_strdup_printf
(
"<span weight=
\"
bold
\"
size=
\"
larger
\"
>%s</span>%s%s"
,
(
primary
?
primary_esc
:
""
),
(
primary
&&
secondary
?
"
\n
"
:
""
),
(
secondary
?
secondary_esc
:
""
));
g_free
(
primary_esc
);
g_free
(
secondary_esc
);
label
=
gtk_label_new
(
NULL
);
gtk_label_set_markup
(
GTK_LABEL
(
label
),
label_text
);
gtk_label_set_line_wrap
(
GTK_LABEL
(
label
),
TRUE
);
gtk_label_set_xalign
(
GTK_LABEL
(
label
),
0
);
gtk_label_set_yalign
(
GTK_LABEL
(
label
),
0
);
gtk_box_pack_start
(
GTK_BOX
(
vbox
),
label
,
FALSE
,
FALSE
,
0
);
gtk_widget_show
(
label
);
g_free
(
label_text
);
/* +1 is for the automagically created Status column. */
col_num
=
g_list_length
(
results
->
columns
)
+
1
;
/* Setup the list model */
col_types
=
g_new0
(
GType
,
col_num
);
/* There always is this first column. */
col_types
[
0
]
=
GDK_TYPE_PIXBUF
;
for
(
i
=
1
;
i
<
col_num
;
i
++
)
{
col_types
[
i
]
=
G_TYPE_STRING
;
}
model
=
gtk_list_store_newv
(
col_num
,
col_types
);
g_free
(
col_types
);
/* Setup the treeview */
treeview
=
gtk_tree_view_new_with_model
(
GTK_TREE_MODEL
(
model
));
g_object_unref
(
G_OBJECT
(
model
));
gtk_widget_set_size_request
(
treeview
,
500
,
400
);
gtk_tree_selection_set_mode
(
gtk_tree_view_get_selection
(
GTK_TREE_VIEW
(
treeview
)),
GTK_SELECTION_SINGLE
);
gtk_tree_view_set_headers_visible
(
GTK_TREE_VIEW
(
treeview
),
TRUE
);
gtk_box_pack_start
(
GTK_BOX
(
vbox
),
pidgin_make_scrollable
(
treeview
,
GTK_POLICY_AUTOMATIC
,
GTK_POLICY_ALWAYS
,
GTK_SHADOW_IN
,
-1
,
-1
),
TRUE
,
TRUE
,
0
);
gtk_widget_show
(
treeview
);
renderer
=
gtk_cell_renderer_pixbuf_new
();
gtk_tree_view_insert_column_with_attributes
(
GTK_TREE_VIEW
(
treeview
),
-1
,
""
,
renderer
,
"pixbuf"
,
0
,
NULL
);
i
=
1
;
for
(
columniter
=
results
->
columns
;
columniter
!=
NULL
;
columniter
=
columniter
->
next
)
{
PurpleNotifySearchColumn
*
column
=
columniter
->
data
;
renderer
=
gtk_cell_renderer_text_new
();
gtk_tree_view_insert_column_with_attributes
(
GTK_TREE_VIEW
(
treeview
),
-1
,
purple_notify_searchresult_column_get_title
(
column
),
renderer
,
"text"
,
i
,
NULL
);
if
(
!
purple_notify_searchresult_column_is_visible
(
column
))
gtk_tree_view_column_set_visible
(
gtk_tree_view_get_column
(
GTK_TREE_VIEW
(
treeview
),
i
),
FALSE
);
i
++
;
}
for
(
l
=
results
->
buttons
;
l
;
l
=
l
->
next
)
{
PurpleNotifySearchButton
*
b
=
l
->
data
;
GtkWidget
*
button
=
NULL
;
switch
(
b
->
type
)
{
case
PURPLE_NOTIFY_BUTTON_LABELED
:
if
(
b
->
label
)
{
button
=
gtk_dialog_add_button
(
GTK_DIALOG
(
window
),
b
->
label
,
GTK_RESPONSE_NONE
);
}
else
{
purple_debug_warning
(
"gtknotify"
,
"Missing button label
\n
"
);
}
break
;
case
PURPLE_NOTIFY_BUTTON_CONTINUE
:
button
=
gtk_dialog_add_button
(
GTK_DIALOG
(
window
),
GTK_STOCK_GO_FORWARD
,
GTK_RESPONSE_NONE
);
break
;
case
PURPLE_NOTIFY_BUTTON_ADD
:
button
=
gtk_dialog_add_button
(
GTK_DIALOG
(
window
),
GTK_STOCK_ADD
,
GTK_RESPONSE_NONE
);
break
;
case
PURPLE_NOTIFY_BUTTON_INFO
:
button
=
gtk_dialog_add_button
(
GTK_DIALOG
(
window
),
PIDGIN_STOCK_TOOLBAR_USER_INFO
,
GTK_RESPONSE_NONE
);
break
;
case
PURPLE_NOTIFY_BUTTON_IM
:
button
=
gtk_dialog_add_button
(
GTK_DIALOG
(
window
),
PIDGIN_STOCK_TOOLBAR_MESSAGE_NEW
,
GTK_RESPONSE_NONE
);
break
;
case
PURPLE_NOTIFY_BUTTON_JOIN
:
button
=
gtk_dialog_add_button
(
GTK_DIALOG
(
window
),
PIDGIN_STOCK_CHAT
,
GTK_RESPONSE_NONE
);
break
;
case
PURPLE_NOTIFY_BUTTON_INVITE
:
button
=
gtk_dialog_add_button
(
GTK_DIALOG
(
window
),
PIDGIN_STOCK_INVITE
,
GTK_RESPONSE_NONE
);
break
;
default
:
purple_debug_warning
(
"gtknotify"
,
"Incorrect button type: %d
\n
"
,
b
->
type
);
}
if
(
button
!=
NULL
)
{
PidginNotifySearchResultsButtonData
*
bd
;
bd
=
g_new0
(
PidginNotifySearchResultsButtonData
,
1
);
bd
->
button
=
b
;
bd
->
data
=
data
;
g_signal_connect
(
G_OBJECT
(
button
),
"clicked"
,
G_CALLBACK
(
searchresults_callback_wrapper_cb
),
bd
);
g_signal_connect_swapped
(
G_OBJECT
(
button
),
"destroy"
,
G_CALLBACK
(
g_free
),
bd
);
}
}
/* Add the Close button */
close_button
=
gtk_dialog_add_button
(
GTK_DIALOG
(
window
),
GTK_STOCK_CLOSE
,
GTK_RESPONSE_CLOSE
);
g_signal_connect_swapped
(
G_OBJECT
(
close_button
),
"clicked"
,
G_CALLBACK
(
searchresults_close_cb
),
data
);
data
->
account
=
purple_connection_get_account
(
gc
);
data
->
model
=
model
;
data
->
treeview
=
treeview
;
data
->
window
=
window
;
/* Insert rows. */
pidgin_notify_searchresults_new_rows
(
gc
,
results
,
data
);
/* Show the window */
pidgin_auto_parent_window
(
window
);
gtk_widget_show
(
window
);
return
data
;
}
/** Xerox'ed from Finch! How the tables have turned!! ;) **/
/** User information. **/
static
GHashTable
*
userinfo
;
static
char
*
userinfo_hash
(
PurpleAccount
*
account
,
const
char
*
who
)
{
char
key
[
256
];
g_snprintf
(
key
,
sizeof
(
key
),
"%s - %s"
,
purple_account_get_username
(
account
),
purple_normalize
(
account
,
who
));
return
g_utf8_strup
(
key
,
-1
);
}
static
void
remove_userinfo
(
GtkWidget
*
widget
,
gpointer
key
)
{
PidginUserInfo
*
pinfo
=
g_hash_table_lookup
(
userinfo
,
key
);
while
(
pinfo
->
count
--
)
purple_notify_close
(
PURPLE_NOTIFY_USERINFO
,
widget
);
g_hash_table_remove
(
userinfo
,
key
);
}
static
void
*
pidgin_notify_userinfo
(
PurpleConnection
*
gc
,
const
char
*
who
,
PurpleNotifyUserInfo
*
user_info
)
{
char
*
info
;
void
*
ui_handle
;
char
*
key
=
userinfo_hash
(
purple_connection_get_account
(
gc
),
who
);
PidginUserInfo
*
pinfo
=
NULL
;
if
(
!
userinfo
)
{
userinfo
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
g_free
);
}
info
=
purple_notify_user_info_get_text_with_newline
(
user_info
,
"<br />"
);
pinfo
=
g_hash_table_lookup
(
userinfo
,
key
);
if
(
pinfo
!=
NULL
)
{
GtkWidget
*
view
=
g_object_get_data
(
G_OBJECT
(
pinfo
->
window
),
"view-widget"
);
GtkTextBuffer
*
buffer
=
gtk_text_view_get_buffer
(
GTK_TEXT_VIEW
(
view
));
char
*
linked_text
=
purple_markup_linkify
(
info
);
talkatu_markup_set_html
(
TALKATU_BUFFER
(
buffer
),
linked_text
,
-1
);
g_free
(
linked_text
);
g_free
(
key
);
ui_handle
=
pinfo
->
window
;
pinfo
->
count
++
;
}
else
{
char
*
primary
=
g_strdup_printf
(
_
(
"Info for %s"
),
who
);
ui_handle
=
pidgin_notify_formatted
(
_
(
"Buddy Information"
),
primary
,
NULL
,
info
);
g_signal_handlers_disconnect_by_func
(
G_OBJECT
(
ui_handle
),
G_CALLBACK
(
formatted_close_cb
),
NULL
);
g_signal_connect
(
G_OBJECT
(
ui_handle
),
"destroy"
,
G_CALLBACK
(
remove_userinfo
),
key
);
g_free
(
primary
);
pinfo
=
g_new0
(
PidginUserInfo
,
1
);
pinfo
->
window
=
ui_handle
;
pinfo
->
count
=
1
;
g_hash_table_insert
(
userinfo
,
key
,
pinfo
);
}
g_free
(
info
);
return
ui_handle
;
}
static
void
pidgin_close_notify
(
PurpleNotifyType
type
,
void
*
ui_handle
)
{
if
(
type
==
PURPLE_NOTIFY_EMAIL
||
type
==
PURPLE_NOTIFY_EMAILS
)
{
PidginNotifyMailData
*
data
=
(
PidginNotifyMailData
*
)
ui_handle
;
if
(
data
)
{
g_free
(
data
->
url
);
g_free
(
data
);
}
}
else
if
(
type
==
PURPLE_NOTIFY_SEARCHRESULTS
)
{
PidginNotifySearchResultsData
*
data
=
(
PidginNotifySearchResultsData
*
)
ui_handle
;
gtk_widget_destroy
(
data
->
window
);
purple_notify_searchresults_free
(
data
->
results
);
g_free
(
data
);
}
else
if
(
ui_handle
!=
NULL
)
gtk_widget_destroy
(
GTK_WIDGET
(
ui_handle
));
}
#ifndef _WIN32
static
gboolean
uri_command
(
GSList
*
arg_list
,
gboolean
sync
)
{
gchar
*
tmp
;
GError
*
error
=
NULL
;
GSList
*
it
;
gchar
**
argv
;
gint
argc
,
i
;
gchar
*
program
;
g_return_val_if_fail
(
arg_list
!=
NULL
,
FALSE
);
program
=
arg_list
->
data
;
purple_debug_misc
(
"gtknotify"
,
"Executing %s (%s)
\n
"
,
program
,
sync
?
"sync"
:
"async"
);
if
(
!
purple_program_is_valid
(
program
))
{
purple_debug_error
(
"gtknotify"
,
"Command
\"
%s
\"
is invalid
\n
"
,
program
);
tmp
=
g_strdup_printf
(
_
(
"The browser command
\"
%s
\"
is invalid."
),
program
?
program
:
"(null)"
);
purple_notify_error
(
NULL
,
NULL
,
_
(
"Unable to open URL"
),
tmp
,
NULL
);
g_free
(
tmp
);
return
FALSE
;
}
argc
=
g_slist_length
(
arg_list
);
argv
=
g_new
(
gchar
*
,
argc
+
1
);
i
=
0
;
for
(
it
=
arg_list
;
it
;
it
=
g_slist_next
(
it
))
{
if
(
purple_debug_is_verbose
())
{
purple_debug_misc
(
"gtknotify"
,
"argv[%d] =
\"
%s
\"\n
"
,
i
,
(
gchar
*
)
it
->
data
);
}
argv
[
i
++
]
=
it
->
data
;
}
argv
[
i
]
=
NULL
;
if
(
sync
)
{
gint
exit_status
=
0
;
if
(
g_spawn_sync
(
NULL
,
argv
,
NULL
,
G_SPAWN_SEARCH_PATH
|
G_SPAWN_STDOUT_TO_DEV_NULL
|
G_SPAWN_STDERR_TO_DEV_NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
&
exit_status
,
&
error
)
&&
exit_status
==
0
)
{
g_free
(
argv
);
return
TRUE
;
}
purple_debug_error
(
"gtknotify"
,
"Error launching
\"
%s
\"
: %s (status: %d)
\n
"
,
program
,
error
?
error
->
message
:
"(null)"
,
exit_status
);
tmp
=
g_strdup_printf
(
_
(
"Error launching
\"
%s
\"
: %s"
),
program
,
error
?
error
->
message
:
"(null)"
);
g_error_free
(
error
);
purple_notify_error
(
NULL
,
NULL
,
_
(
"Unable to open URL"
),
tmp
,
NULL
);
g_free
(
tmp
);
g_free
(
argv
);
return
FALSE
;
}
if
(
g_spawn_async
(
NULL
,
argv
,
NULL
,
G_SPAWN_SEARCH_PATH
|
G_SPAWN_STDOUT_TO_DEV_NULL
|
G_SPAWN_STDERR_TO_DEV_NULL
,
NULL
,
NULL
,
NULL
,
&
error
))
{
g_free
(
argv
);
return
TRUE
;
}
purple_debug_warning
(
"gtknotify"
,
"Error launching
\"
%s
\"
: %s
\n
"
,
program
,
error
?
error
->
message
:
"(null)"
);
g_error_free
(
error
);
g_free
(
argv
);
return
FALSE
;
}
#endif
/* _WIN32 */
static
void
*
pidgin_notify_uri
(
const
char
*
uri
)
{
#ifndef _WIN32
const
char
*
web_browser
;
int
place
;
gchar
*
uri_escaped
,
*
uri_custom
=
NULL
;
GSList
*
argv
=
NULL
,
*
argv_remote
=
NULL
;
gchar
**
usercmd_argv
=
NULL
;
uri_escaped
=
purple_uri_escape_for_open
(
uri
);
web_browser
=
purple_prefs_get_string
(
PIDGIN_PREFS_ROOT
"/browsers/browser"
);
place
=
purple_prefs_get_int
(
PIDGIN_PREFS_ROOT
"/browsers/place"
);
/* if they are running gnome, use the gnome web browser */
if
(
purple_running_gnome
()
==
TRUE
)
{
char
*
tmp
=
g_find_program_in_path
(
"xdg-open"
);
if
(
tmp
==
NULL
)
argv
=
g_slist_append
(
argv
,
"gnome-open"
);
else
argv
=
g_slist_append
(
argv
,
"xdg-open"
);
g_free
(
tmp
);
argv
=
g_slist_append
(
argv
,
uri_escaped
);
}
else
if
(
purple_running_osx
()
==
TRUE
)
{
argv
=
g_slist_append
(
argv
,
"open"
);
argv
=
g_slist_append
(
argv
,
uri_escaped
);
}
else
if
(
purple_strequal
(
web_browser
,
"epiphany"
)
||
purple_strequal
(
web_browser
,
"galeon"
))
{
argv
=
g_slist_append
(
argv
,
(
gpointer
)
web_browser
);
if
(
place
==
PIDGIN_BROWSER_NEW_WINDOW
)
argv
=
g_slist_append
(
argv
,
"-w"
);
else
if
(
place
==
PIDGIN_BROWSER_NEW_TAB
)
argv
=
g_slist_append
(
argv
,
"-n"
);
argv
=
g_slist_append
(
argv
,
uri_escaped
);
}
else
if
(
purple_strequal
(
web_browser
,
"xdg-open"
))
{
argv
=
g_slist_append
(
argv
,
"xdg-open"
);
argv
=
g_slist_append
(
argv
,
uri_escaped
);
}
else
if
(
purple_strequal
(
web_browser
,
"gnome-open"
))
{
argv
=
g_slist_append
(
argv
,
"gnome-open"
);
argv
=
g_slist_append
(
argv
,
uri_escaped
);
}
else
if
(
purple_strequal
(
web_browser
,
"kfmclient"
))
{
argv
=
g_slist_append
(
argv
,
"kfmclient"
);
argv
=
g_slist_append
(
argv
,
"openURL"
);
argv
=
g_slist_append
(
argv
,
uri_escaped
);
/*
* Does Konqueror have options to open in new tab
* and/or current window?
*/
}
else
if
(
purple_strequal
(
web_browser
,
"mozilla"
)
||
purple_strequal
(
web_browser
,
"mozilla-firebird"
)
||
purple_strequal
(
web_browser
,
"firefox"
)
||
purple_strequal
(
web_browser
,
"seamonkey"
))
{
argv
=
g_slist_append
(
argv
,
(
gpointer
)
web_browser
);
argv
=
g_slist_append
(
argv
,
uri_escaped
);
g_assert
(
uri_custom
==
NULL
);
if
(
place
==
PIDGIN_BROWSER_NEW_WINDOW
)
{
uri_custom
=
g_strdup_printf
(
"openURL(%s,new-window)"
,
uri_escaped
);
}
else
if
(
place
==
PIDGIN_BROWSER_NEW_TAB
)
{
uri_custom
=
g_strdup_printf
(
"openURL(%s,new-tab)"
,
uri_escaped
);
}
if
(
uri_custom
!=
NULL
)
{
argv_remote
=
g_slist_append
(
argv_remote
,
(
gpointer
)
web_browser
);
/* Firefox 0.9 and higher require a "-a firefox" option
* when using -remote commands. This breaks older
* versions of mozilla. So we include this other handly
* little string when calling firefox. If the API for
* remote calls changes any more in firefox then firefox
* should probably be split apart from mozilla-firebird
* and mozilla... but this is good for now.
*/
if
(
purple_strequal
(
web_browser
,
"firefox"
))
{
argv_remote
=
g_slist_append
(
argv_remote
,
"-a"
);
argv_remote
=
g_slist_append
(
argv_remote
,
"firefox"
);
}
argv_remote
=
g_slist_append
(
argv_remote
,
"-remote"
);
argv_remote
=
g_slist_append
(
argv_remote
,
uri_custom
);
}
}
else
if
(
purple_strequal
(
web_browser
,
"opera"
))
{
argv
=
g_slist_append
(
argv
,
"opera"
);
if
(
place
==
PIDGIN_BROWSER_NEW_WINDOW
)
argv
=
g_slist_append
(
argv
,
"-newwindow"
);
else
if
(
place
==
PIDGIN_BROWSER_NEW_TAB
)
argv
=
g_slist_append
(
argv
,
"-newpage"
);
/* `opera -remote "openURL(%s)"` command causes Pidgin to hang,
* if there is no Opera instance running.
*/
argv
=
g_slist_append
(
argv
,
uri_escaped
);
}
else
if
(
purple_strequal
(
web_browser
,
"google-chrome"
))
{
/* Google Chrome doesn't have command-line arguments that
* control the opening of links from external calls. This is
* controlled solely from a preference within Google Chrome.
*/
argv
=
g_slist_append
(
argv
,
"google-chrome"
);
argv
=
g_slist_append
(
argv
,
uri_escaped
);
}
else
if
(
purple_strequal
(
web_browser
,
"chrome"
))
{
/* Chromium doesn't have command-line arguments that control
* the opening of links from external calls. This is controlled
* solely from a preference within Chromium.
*/
argv
=
g_slist_append
(
argv
,
"chrome"
);
argv
=
g_slist_append
(
argv
,
uri_escaped
);
}
else
if
(
purple_strequal
(
web_browser
,
"chromium-browser"
))
{
/* Chromium doesn't have command-line arguments that control the
* opening of links from external calls. This is controlled
* solely from a preference within Chromium.
*/
argv
=
g_slist_append
(
argv
,
"chromium-browser"
);
argv
=
g_slist_append
(
argv
,
uri_escaped
);
}
else
if
(
purple_strequal
(
web_browser
,
"custom"
))
{
GError
*
error
=
NULL
;
const
char
*
usercmd_command
;
gint
usercmd_argc
,
i
;
gboolean
uri_added
=
FALSE
;
usercmd_command
=
purple_prefs_get_string
(
PIDGIN_PREFS_ROOT
"/browsers/manual_command"
);
if
(
usercmd_command
==
NULL
||
*
usercmd_command
==
'\0'
)
{
purple_notify_error
(
NULL
,
NULL
,
_
(
"Unable to open URL"
),
_
(
"The 'Manual' browser command has been "
"chosen, but no command has been set."
),
NULL
);
g_free
(
uri_escaped
);
return
NULL
;
}
if
(
!
g_shell_parse_argv
(
usercmd_command
,
&
usercmd_argc
,
&
usercmd_argv
,
&
error
))
{
purple_notify_error
(
NULL
,
NULL
,
_
(
"Unable to open URL: "
"the 'Manual' browser command seems invalid."
),
error
?
error
->
message
:
NULL
,
NULL
);
g_error_free
(
error
);
g_free
(
uri_escaped
);
return
NULL
;
}
for
(
i
=
0
;
i
<
usercmd_argc
;
i
++
)
{
gchar
*
cmd_part
=
usercmd_argv
[
i
];
if
(
uri_added
||
strstr
(
cmd_part
,
"%s"
)
==
NULL
)
{
argv
=
g_slist_append
(
argv
,
cmd_part
);
continue
;
}
uri_custom
=
purple_strreplace
(
cmd_part
,
"%s"
,
uri_escaped
);
argv
=
g_slist_append
(
argv
,
uri_custom
);
uri_added
=
TRUE
;
}
/* There is no "%s" in the browser command. Assume the user
* wanted the URL tacked on to the end of the command.
*/
if
(
!
uri_added
)
argv
=
g_slist_append
(
argv
,
uri_escaped
);
}
if
(
argv_remote
!=
NULL
)
{
/* try the remote command first */
if
(
!
uri_command
(
argv_remote
,
TRUE
))
uri_command
(
argv
,
FALSE
);
}
else
uri_command
(
argv
,
FALSE
);
g_strfreev
(
usercmd_argv
);
g_free
(
uri_escaped
);
g_free
(
uri_custom
);
g_slist_free
(
argv
);
g_slist_free
(
argv_remote
);
#else
/* !_WIN32 */
winpidgin_notify_uri
(
uri
);
#endif
/* !_WIN32 */
return
NULL
;
}
void
pidgin_notify_pounce_add
(
PurpleAccount
*
account
,
PurplePounce
*
pounce
,
const
char
*
alias
,
const
char
*
event
,
const
char
*
message
,
const
char
*
date
)
{
GdkPixbuf
*
icon
;
GtkTreeIter
iter
;
PidginNotifyPounceData
*
pounce_data
;
gboolean
first
=
(
pounce_dialog
==
NULL
);
if
(
pounce_dialog
==
NULL
)
pounce_dialog
=
pidgin_create_notification_dialog
(
PIDGIN_NOTIFY_POUNCE
);
icon
=
pidgin_create_protocol_icon
(
account
,
PIDGIN_PROTOCOL_ICON_SMALL
);
pounce_data
=
g_new
(
PidginNotifyPounceData
,
1
);
pounce_data
->
account
=
account
;
pounce_data
->
pounce
=
pounce
;
pounce_data
->
pouncee
=
g_strdup
(
purple_pounce_get_pouncee
(
pounce
));
gtk_tree_store_append
(
pounce_dialog
->
treemodel
,
&
iter
,
NULL
);
gtk_tree_store_set
(
pounce_dialog
->
treemodel
,
&
iter
,
PIDGIN_POUNCE_ICON
,
icon
,
PIDGIN_POUNCE_ALIAS
,
alias
,
PIDGIN_POUNCE_EVENT
,
event
,
PIDGIN_POUNCE_TEXT
,
(
message
!=
NULL
)
?
message
:
_
(
"No message"
),
PIDGIN_POUNCE_DATE
,
date
,
PIDGIN_POUNCE_DATA
,
pounce_data
,
-1
);
if
(
first
)
{
GtkTreeSelection
*
selection
=
gtk_tree_view_get_selection
(
GTK_TREE_VIEW
(
pounce_dialog
->
treeview
));
gtk_tree_selection_select_iter
(
selection
,
&
iter
);
}
if
(
icon
)
g_object_unref
(
icon
);
gtk_widget_show_all
(
pounce_dialog
->
dialog
);
}
static
PidginNotifyDialog
*
pidgin_create_notification_dialog
(
PidginNotifyType
type
)
{
GtkTreeStore
*
model
=
NULL
;
GtkWidget
*
dialog
=
NULL
;
GtkWidget
*
label
=
NULL
;
GtkCellRenderer
*
rend
;
GtkTreeViewColumn
*
column
;
GtkWidget
*
button
=
NULL
;
GtkWidget
*
vbox
=
NULL
;
GtkTreeSelection
*
sel
;
PidginNotifyDialog
*
spec_dialog
=
NULL
;
g_return_val_if_fail
(
type
<
PIDGIN_NOTIFY_TYPES
,
NULL
);
if
(
type
==
PIDGIN_NOTIFY_MAIL
)
{
g_return_val_if_fail
(
mail_dialog
==
NULL
,
mail_dialog
);
model
=
gtk_tree_store_new
(
COLUMNS_PIDGIN_MAIL
,
GDK_TYPE_PIXBUF
,
G_TYPE_STRING
,
G_TYPE_POINTER
);
}
else
if
(
type
==
PIDGIN_NOTIFY_POUNCE
)
{
g_return_val_if_fail
(
pounce_dialog
==
NULL
,
pounce_dialog
);
model
=
gtk_tree_store_new
(
COLUMNS_PIDGIN_POUNCE
,
GDK_TYPE_PIXBUF
,
G_TYPE_STRING
,
G_TYPE_STRING
,
G_TYPE_STRING
,
G_TYPE_STRING
,
G_TYPE_POINTER
);
}
dialog
=
gtk_dialog_new
();
/* Vertical box */
vbox
=
gtk_dialog_get_content_area
(
GTK_DIALOG
(
dialog
));
/* Setup the dialog */
gtk_container_set_border_width
(
GTK_CONTAINER
(
dialog
),
PIDGIN_HIG_BOX_SPACE
);
gtk_container_set_border_width
(
GTK_CONTAINER
(
vbox
),
PIDGIN_HIG_BOX_SPACE
);
gtk_box_set_spacing
(
GTK_BOX
(
vbox
),
PIDGIN_HIG_BORDER
);
/* Golden ratio it up! */
gtk_widget_set_size_request
(
dialog
,
550
,
400
);
spec_dialog
=
g_new0
(
PidginNotifyDialog
,
1
);
spec_dialog
->
dialog
=
dialog
;
spec_dialog
->
treemodel
=
model
;
spec_dialog
->
treeview
=
gtk_tree_view_new_with_model
(
GTK_TREE_MODEL
(
model
));
g_object_unref
(
G_OBJECT
(
model
));
if
(
type
==
PIDGIN_NOTIFY_MAIL
)
{
gtk_window_set_title
(
GTK_WINDOW
(
dialog
),
_
(
"New Mail"
));
gtk_window_set_role
(
GTK_WINDOW
(
dialog
),
"new_mail_detailed"
);
g_signal_connect
(
G_OBJECT
(
dialog
),
"focus-in-event"
,
G_CALLBACK
(
mail_window_focus_cb
),
NULL
);
gtk_dialog_add_button
(
GTK_DIALOG
(
dialog
),
_
(
"Open All Messages"
),
GTK_RESPONSE_ACCEPT
);
button
=
gtk_dialog_add_button
(
GTK_DIALOG
(
dialog
),
PIDGIN_STOCK_OPEN_MAIL
,
GTK_RESPONSE_YES
);
spec_dialog
->
open_button
=
button
;
gtk_tree_view_set_headers_visible
(
GTK_TREE_VIEW
(
spec_dialog
->
treeview
),
FALSE
);
gtk_tree_view_set_search_column
(
GTK_TREE_VIEW
(
spec_dialog
->
treeview
),
PIDGIN_MAIL_TEXT
);
gtk_tree_view_set_search_equal_func
(
GTK_TREE_VIEW
(
spec_dialog
->
treeview
),
pidgin_tree_view_search_equal_func
,
NULL
,
NULL
);
sel
=
gtk_tree_view_get_selection
(
GTK_TREE_VIEW
(
spec_dialog
->
treeview
));
gtk_tree_selection_set_mode
(
sel
,
GTK_SELECTION_BROWSE
);
g_signal_connect
(
G_OBJECT
(
dialog
),
"response"
,
G_CALLBACK
(
email_response_cb
),
spec_dialog
);
g_signal_connect
(
G_OBJECT
(
sel
),
"changed"
,
G_CALLBACK
(
selection_changed_cb
),
spec_dialog
);
g_signal_connect
(
G_OBJECT
(
spec_dialog
->
treeview
),
"row-activated"
,
G_CALLBACK
(
email_row_activated_cb
),
NULL
);
column
=
gtk_tree_view_column_new
();
gtk_tree_view_column_set_resizable
(
column
,
TRUE
);
rend
=
gtk_cell_renderer_pixbuf_new
();
gtk_tree_view_column_pack_start
(
column
,
rend
,
FALSE
);
gtk_tree_view_column_set_attributes
(
column
,
rend
,
"pixbuf"
,
PIDGIN_MAIL_ICON
,
NULL
);
rend
=
gtk_cell_renderer_text_new
();
gtk_tree_view_column_pack_start
(
column
,
rend
,
TRUE
);
gtk_tree_view_column_set_attributes
(
column
,
rend
,
"markup"
,
PIDGIN_MAIL_TEXT
,
NULL
);
gtk_tree_view_append_column
(
GTK_TREE_VIEW
(
spec_dialog
->
treeview
),
column
);
label
=
gtk_label_new
(
NULL
);
gtk_label_set_markup
(
GTK_LABEL
(
label
),
_
(
"<span weight=
\"
bold
\"
size=
\"
larger
\"
>You have mail!</span>"
));
}
else
if
(
type
==
PIDGIN_NOTIFY_POUNCE
)
{
gtk_window_set_title
(
GTK_WINDOW
(
dialog
),
_
(
"New Pounces"
));
button
=
gtk_dialog_add_button
(
GTK_DIALOG
(
dialog
),
_
(
"IM"
),
GTK_RESPONSE_YES
);
gtk_widget_set_sensitive
(
button
,
FALSE
);
spec_dialog
->
open_button
=
button
;
button
=
gtk_dialog_add_button
(
GTK_DIALOG
(
dialog
),
PIDGIN_STOCK_MODIFY
,
GTK_RESPONSE_APPLY
);
gtk_widget_set_sensitive
(
button
,
FALSE
);
spec_dialog
->
edit_button
=
button
;
/* Translators: Make sure you translate "Dismiss" differently than
"close"! This string is used in the "You have pounced" dialog
that appears when one of your Buddy Pounces is triggered. In
this context "Dismiss" means "I acknowledge that I've seen that
this pounce was triggered--remove it from this list." Translating
it as "Remove" is acceptable if you can't think of a more precise
word. */
button
=
gtk_dialog_add_button
(
GTK_DIALOG
(
dialog
),
_
(
"Dismiss"
),
GTK_RESPONSE_NO
);
gtk_widget_set_sensitive
(
button
,
FALSE
);
spec_dialog
->
dismiss_button
=
button
;
g_signal_connect
(
G_OBJECT
(
dialog
),
"response"
,
G_CALLBACK
(
pounce_response_cb
),
spec_dialog
);
column
=
gtk_tree_view_column_new
();
gtk_tree_view_column_set_title
(
column
,
_
(
"Buddy"
));
gtk_tree_view_column_set_resizable
(
column
,
TRUE
);
rend
=
gtk_cell_renderer_pixbuf_new
();
gtk_tree_view_column_pack_start
(
column
,
rend
,
FALSE
);
gtk_tree_view_column_set_attributes
(
column
,
rend
,
"pixbuf"
,
PIDGIN_POUNCE_ICON
,
NULL
);
rend
=
gtk_cell_renderer_text_new
();
gtk_tree_view_column_pack_start
(
column
,
rend
,
FALSE
);
gtk_tree_view_column_add_attribute
(
column
,
rend
,
"text"
,
PIDGIN_POUNCE_ALIAS
);
gtk_tree_view_append_column
(
GTK_TREE_VIEW
(
spec_dialog
->
treeview
),
column
);
column
=
gtk_tree_view_column_new
();
gtk_tree_view_column_set_title
(
column
,
_
(
"Event"
));
gtk_tree_view_column_set_resizable
(
column
,
TRUE
);
rend
=
gtk_cell_renderer_text_new
();
gtk_tree_view_column_pack_start
(
column
,
rend
,
FALSE
);
gtk_tree_view_column_add_attribute
(
column
,
rend
,
"text"
,
PIDGIN_POUNCE_EVENT
);
gtk_tree_view_append_column
(
GTK_TREE_VIEW
(
spec_dialog
->
treeview
),
column
);
column
=
gtk_tree_view_column_new
();
gtk_tree_view_column_set_title
(
column
,
_
(
"Message"
));
gtk_tree_view_column_set_resizable
(
column
,
TRUE
);
rend
=
gtk_cell_renderer_text_new
();
gtk_tree_view_column_pack_start
(
column
,
rend
,
FALSE
);
gtk_tree_view_column_add_attribute
(
column
,
rend
,
"text"
,
PIDGIN_POUNCE_TEXT
);
gtk_tree_view_append_column
(
GTK_TREE_VIEW
(
spec_dialog
->
treeview
),
column
);
column
=
gtk_tree_view_column_new
();
gtk_tree_view_column_set_title
(
column
,
_
(
"Date"
));
gtk_tree_view_column_set_resizable
(
column
,
TRUE
);
rend
=
gtk_cell_renderer_text_new
();
gtk_tree_view_column_pack_start
(
column
,
rend
,
FALSE
);
gtk_tree_view_column_add_attribute
(
column
,
rend
,
"text"
,
PIDGIN_POUNCE_DATE
);
gtk_tree_view_append_column
(
GTK_TREE_VIEW
(
spec_dialog
->
treeview
),
column
);
label
=
gtk_label_new
(
NULL
);
gtk_label_set_markup
(
GTK_LABEL
(
label
),
_
(
"<span weight=
\"
bold
\"
size=
\"
larger
\"
>You have pounced!</span>"
));
sel
=
gtk_tree_view_get_selection
(
GTK_TREE_VIEW
(
spec_dialog
->
treeview
));
gtk_tree_selection_set_mode
(
sel
,
GTK_SELECTION_MULTIPLE
);
g_signal_connect
(
G_OBJECT
(
sel
),
"changed"
,
G_CALLBACK
(
pounce_row_selected_cb
),
NULL
);
g_signal_connect
(
G_OBJECT
(
spec_dialog
->
treeview
),
"row-activated"
,
G_CALLBACK
(
pounce_response_open_ims
),
NULL
);
}
gtk_dialog_add_button
(
GTK_DIALOG
(
dialog
),
GTK_STOCK_CLOSE
,
GTK_RESPONSE_CLOSE
);
gtk_label_set_line_wrap
(
GTK_LABEL
(
label
),
TRUE
);
gtk_label_set_xalign
(
GTK_LABEL
(
label
),
0
);
gtk_label_set_yalign
(
GTK_LABEL
(
label
),
0
);
gtk_box_pack_start
(
GTK_BOX
(
vbox
),
label
,
FALSE
,
FALSE
,
0
);
gtk_box_pack_start
(
GTK_BOX
(
vbox
),
pidgin_make_scrollable
(
spec_dialog
->
treeview
,
GTK_POLICY_AUTOMATIC
,
GTK_POLICY_ALWAYS
,
GTK_SHADOW_IN
,
-1
,
-1
),
TRUE
,
TRUE
,
2
);
return
spec_dialog
;
}
static
void
signed_off_cb
(
PurpleConnection
*
gc
,
gpointer
unused
)
{
/* Clear any pending emails for this account */
pidgin_notify_emails
(
gc
,
0
,
FALSE
,
NULL
,
NULL
,
NULL
,
NULL
);
if
(
mail_dialog
!=
NULL
&&
mail_dialog
->
total_count
==
0
)
reset_mail_dialog
(
NULL
);
}
static
void
*
pidgin_notify_get_handle
(
void
)
{
static
int
handle
;
return
&
handle
;
}
void
pidgin_notify_init
(
void
)
{
void
*
handle
=
pidgin_notify_get_handle
();
purple_signal_connect
(
purple_connections_get_handle
(),
"signed-off"
,
handle
,
PURPLE_CALLBACK
(
signed_off_cb
),
NULL
);
}
void
pidgin_notify_uninit
(
void
)
{
purple_signals_disconnect_by_handle
(
pidgin_notify_get_handle
());
}
static
PurpleNotifyUiOps
ops
=
{
pidgin_notify_message
,
pidgin_notify_email
,
pidgin_notify_emails
,
pidgin_notify_formatted
,
pidgin_notify_searchresults
,
pidgin_notify_searchresults_new_rows
,
pidgin_notify_userinfo
,
pidgin_notify_uri
,
pidgin_close_notify
,
NULL
,
NULL
,
NULL
,
NULL
};
PurpleNotifyUiOps
*
pidgin_notify_get_ui_ops
(
void
)
{
return
&
ops
;
}