pidgin/purple-plugin-pack
Clone
Summary
Browse
Changes
Graph
added a cleanup function to autogen.sh which gets called on SIGINT to cleanup our temp files (autogen-??????)
2009-10-27, Gary Kramlich
f8733e54f6fe
added a cleanup function to autogen.sh which gets called on SIGINT to cleanup our temp files (autogen-??????)
/*--------------------------------------------------------------------------*
* AUTOPROFILE *
* *
* A Purple away message and profile manager that supports dynamic text *
* *
* AutoProfile is the legal property of its developers. 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
*--------------------------------------------------------------------------*/
#include
"autoprofile.h"
#include
"widget.h"
#include
"request.h"
#include
"gtkprefs.h"
#include
"gtkimhtml.h"
#define AP_RESPONSE_CHOOSE 98125
static
GtkWidget
*
dialog_box
=
NULL
;
static
GtkWidget
*
dialog_box_contents
=
NULL
;
static
GtkWidget
*
dialog_box_preview
=
NULL
;
static
struct
widget
*
dialog_box_widget
=
NULL
;
static
GStaticMutex
preview_mutex
=
G_STATIC_MUTEX_INIT
;
static
GtkWidget
*
component_dialog
=
NULL
;
static
GtkWidget
*
choose_button
=
NULL
;
static
GtkWidget
*
widget_dialog
=
NULL
;
static
GtkWidget
*
delete_button
=
NULL
;
static
GtkWidget
*
rename_button
=
NULL
;
static
GtkListStore
*
tree_list
=
NULL
;
static
GHashTable
*
pref_names
=
NULL
;
static
void
component_dialog_show
();
void
ap_widget_prefs_updated
(
struct
widget
*
w
)
{
gchar
*
output
;
if
(
dialog_box_preview
==
NULL
)
return
;
if
(
w
!=
dialog_box_widget
)
return
;
// TODO: Investigate how laggy this is, possibly add a timeout
output
=
w
->
component
->
generate
(
w
);
g_static_mutex_lock
(
&
preview_mutex
);
gtk_imhtml_clear
(
GTK_IMHTML
(
dialog_box_preview
));
gtk_imhtml_append_text
(
GTK_IMHTML
(
dialog_box_preview
),
output
,
GTK_IMHTML_NO_SCROLL
);
g_static_mutex_unlock
(
&
preview_mutex
);
free
(
output
);
}
static
void
update_widget_list
(
GtkListStore
*
ls
)
{
GtkTreeIter
iter
;
GList
*
widgets
,
*
widgets_start
;
struct
widget
*
w
;
GString
*
s
;
s
=
g_string_new
(
""
);
gtk_list_store_clear
(
ls
);
widgets_start
=
widgets
=
ap_widget_get_widgets
();
for
(
widgets
=
widgets_start
;
widgets
!=
NULL
;
widgets
=
widgets
->
next
)
{
gtk_list_store_append
(
ls
,
&
iter
);
w
=
(
struct
widget
*
)
widgets
->
data
;
g_string_printf
(
s
,
"<b>%s</b>"
,
w
->
alias
);
gtk_list_store_set
(
ls
,
&
iter
,
0
,
s
->
str
,
1
,
w
,
-1
);
}
g_list_free
(
widgets_start
);
g_string_free
(
s
,
TRUE
);
}
static
void
refresh_cb
(
GtkWidget
*
widget
,
gpointer
data
)
{
struct
widget
*
w
;
w
=
(
struct
widget
*
)
data
;
ap_widget_prefs_updated
(
w
);
}
/* Widget configuration menu */
static
GtkWidget
*
get_widget_configuration
(
struct
widget
*
w
)
{
GtkWidget
*
config
,
*
hbox
,
*
vbox
,
*
sw
;
GtkWidget
*
label
,
*
button
;
GtkWidget
*
menu
;
GString
*
s
;
gchar
*
output
;
config
=
gtk_vbox_new
(
FALSE
,
0
);
/* Title/Description */
hbox
=
gtk_hbox_new
(
FALSE
,
8
);
gtk_container_set_border_width
(
GTK_CONTAINER
(
hbox
),
6
);
gtk_box_pack_start
(
GTK_BOX
(
config
),
hbox
,
FALSE
,
FALSE
,
0
);
s
=
g_string_new
(
""
);
g_string_printf
(
s
,
"<b>%s:</b> %s"
,
w
->
component
->
name
,
w
->
component
->
description
);
label
=
gtk_label_new
(
""
);
gtk_label_set_markup
(
GTK_LABEL
(
label
),
s
->
str
);
gtk_box_pack_start
(
GTK_BOX
(
hbox
),
label
,
FALSE
,
FALSE
,
0
);
gtk_misc_set_alignment
(
GTK_MISC
(
label
),
0
,
0
);
g_string_free
(
s
,
TRUE
);
/* Separator */
gtk_box_pack_start
(
GTK_BOX
(
config
),
gtk_hseparator_new
(),
FALSE
,
FALSE
,
0
);
/* Preview window */
vbox
=
gtk_vbox_new
(
FALSE
,
6
);
gtk_container_set_border_width
(
GTK_CONTAINER
(
vbox
),
6
);
gtk_box_pack_start
(
GTK_BOX
(
config
),
vbox
,
FALSE
,
FALSE
,
0
);
hbox
=
gtk_hbox_new
(
FALSE
,
8
);
gtk_box_pack_start
(
GTK_BOX
(
vbox
),
hbox
,
FALSE
,
FALSE
,
0
);
label
=
gtk_label_new
(
""
);
gtk_label_set_markup
(
GTK_LABEL
(
label
),
_
(
"<b>Preview</b>"
));
gtk_box_pack_start
(
GTK_BOX
(
hbox
),
label
,
FALSE
,
FALSE
,
0
);
button
=
gtk_button_new_with_label
(
_
(
"Refresh"
));
gtk_box_pack_end
(
GTK_BOX
(
hbox
),
button
,
FALSE
,
FALSE
,
0
);
g_signal_connect
(
G_OBJECT
(
button
),
"clicked"
,
G_CALLBACK
(
refresh_cb
),
w
);
sw
=
gtk_scrolled_window_new
(
NULL
,
NULL
);
gtk_scrolled_window_set_policy
(
GTK_SCROLLED_WINDOW
(
sw
),
GTK_POLICY_NEVER
,
GTK_POLICY_AUTOMATIC
);
gtk_scrolled_window_set_shadow_type
(
GTK_SCROLLED_WINDOW
(
sw
),
GTK_SHADOW_IN
);
gtk_box_pack_start
(
GTK_BOX
(
vbox
),
sw
,
TRUE
,
TRUE
,
0
);
dialog_box_preview
=
gtk_imhtml_new
(
NULL
,
NULL
);
gtk_container_add
(
GTK_CONTAINER
(
sw
),
dialog_box_preview
);
pidgin_setup_imhtml
(
dialog_box_preview
);
output
=
w
->
component
->
generate
(
w
);
gtk_imhtml_append_text
(
GTK_IMHTML
(
dialog_box_preview
),
output
,
GTK_IMHTML_NO_SCROLL
);
free
(
output
);
dialog_box_widget
=
w
;
/* Separator */
gtk_box_pack_start
(
GTK_BOX
(
config
),
gtk_hseparator_new
(),
FALSE
,
FALSE
,
0
);
/* Configuration stuff */
vbox
=
gtk_vbox_new
(
FALSE
,
8
);
gtk_container_set_border_width
(
GTK_CONTAINER
(
vbox
),
6
);
gtk_box_pack_start
(
GTK_BOX
(
config
),
vbox
,
TRUE
,
TRUE
,
0
);
label
=
gtk_label_new
(
""
);
gtk_label_set_markup
(
GTK_LABEL
(
label
),
_
(
"<b>Configuration</b>"
));
gtk_box_pack_start
(
GTK_BOX
(
vbox
),
label
,
FALSE
,
FALSE
,
0
);
gtk_misc_set_alignment
(
GTK_MISC
(
label
),
0
,
0
);
if
(
w
->
component
->
pref_menu
==
NULL
||
(
menu
=
(
w
->
component
->
pref_menu
)
(
w
))
==
NULL
)
{
label
=
gtk_label_new
(
_
(
"No options available for this component"
));
gtk_misc_set_alignment
(
GTK_MISC
(
label
),
0
,
0
);
gtk_box_pack_start
(
GTK_BOX
(
vbox
),
label
,
FALSE
,
FALSE
,
0
);
}
else
{
gtk_box_pack_start
(
GTK_BOX
(
vbox
),
menu
,
TRUE
,
TRUE
,
0
);
}
return
config
;
}
/* Info message */
static
GtkWidget
*
get_info_message
()
{
GtkWidget
*
page
;
GtkWidget
*
aboutwin
;
GtkWidget
*
text
;
/* Make the box */
page
=
gtk_vbox_new
(
FALSE
,
8
);
gtk_container_set_border_width
(
GTK_CONTAINER
(
page
),
12
);
/* Window with info */
aboutwin
=
gtk_scrolled_window_new
(
NULL
,
NULL
);
gtk_scrolled_window_set_policy
(
GTK_SCROLLED_WINDOW
(
aboutwin
),
GTK_POLICY_NEVER
,
GTK_POLICY_ALWAYS
);
gtk_scrolled_window_set_shadow_type
(
GTK_SCROLLED_WINDOW
(
aboutwin
),
GTK_SHADOW_IN
);
gtk_box_pack_start
(
GTK_BOX
(
page
),
aboutwin
,
TRUE
,
TRUE
,
0
);
text
=
gtk_imhtml_new
(
NULL
,
NULL
);
gtk_container_add
(
GTK_CONTAINER
(
aboutwin
),
text
);
pidgin_setup_imhtml
(
text
);
/* Info text */
gtk_imhtml_append_text
(
GTK_IMHTML
(
text
),
_
(
"<b><u>Basic info</u></b><br>"
),
GTK_IMHTML_NO_SCROLL
);
gtk_imhtml_append_text
(
GTK_IMHTML
(
text
),
_
(
"A <b>widget</b> is a little piece/snippet of automatically "
"generated text. There are all sorts of widgets; each type has "
"different content (i.e. a random quote, text from a blog, the "
"song currently playing, etc).<br><br>"
),
GTK_IMHTML_NO_SCROLL
);
gtk_imhtml_append_text
(
GTK_IMHTML
(
text
),
_
(
"To use a widget, simply drag it from the list on the left and "
"drop it into a profile or status message. <i>It's that easy!</i>"
"<br><br>"
),
GTK_IMHTML_NO_SCROLL
);
gtk_imhtml_append_text
(
GTK_IMHTML
(
text
),
_
(
"<b>To edit your profile:</b> "
"Use the
\"
Info/profile
\"
tab in this window.<br>"
),
GTK_IMHTML_NO_SCROLL
);
gtk_imhtml_append_text
(
GTK_IMHTML
(
text
),
_
(
"<b>To edit your available/away/status message:</b> "
"Use the regular Purple interface built into the bottom of the buddy "
"list.<br><br>"
),
GTK_IMHTML_NO_SCROLL
);
gtk_imhtml_append_text
(
GTK_IMHTML
(
text
),
_
(
"<b><u>Advanced Tips</u></b><br>"
),
GTK_IMHTML_NO_SCROLL
);
gtk_imhtml_append_text
(
GTK_IMHTML
(
text
),
_
(
"You can insert a widget into a profile or status by typing its name. "
"To do this, just type
\"
[widget-name]
\"
wherever you want to "
"place a widget (names of widgets are listed on the left). <br><br>"
"<b>You type:</b> The song I am playing now is [iTunesInfo].<br>"
"<b>AutoProfile result:</b> The song I am playing now is "
"The Beatles - Yellow Submarine.<br><br>"
),
GTK_IMHTML_NO_SCROLL
);
return
page
;
}
/* Dialog window actions */
static
void
widget_popup_rename_cb
(
struct
widget
*
w
,
const
char
*
new_text
)
{
GtkTreeIter
iter
;
GValue
val
;
struct
widget
*
cur_widget
;
GString
*
s
;
gtk_tree_model_get_iter_first
(
GTK_TREE_MODEL
(
tree_list
),
&
iter
);
while
(
TRUE
)
{
val
.
g_type
=
0
;
gtk_tree_model_get_value
(
GTK_TREE_MODEL
(
tree_list
),
&
iter
,
1
,
&
val
);
cur_widget
=
g_value_get_pointer
(
&
val
);
if
(
cur_widget
==
w
)
break
;
if
(
!
gtk_tree_model_iter_next
(
GTK_TREE_MODEL
(
tree_list
),
&
iter
))
{
purple_notify_error
(
NULL
,
NULL
,
N_
(
"Unable to change name"
),
N_
(
"The specified widget no longer exists."
));
return
;
}
}
if
(
ap_widget_rename
(
w
,
new_text
))
{
s
=
g_string_new
(
""
);
g_string_printf
(
s
,
"<b>%s</b>"
,
w
->
alias
);
// Set value in ls
gtk_list_store_set
(
tree_list
,
&
iter
,
0
,
s
->
str
,
1
,
w
,
-1
);
g_string_free
(
s
,
TRUE
);
}
else
{
purple_notify_error
(
NULL
,
NULL
,
N_
(
"Unable to change name"
),
N_
(
"The widget name you have specified is already in use."
));
}
}
static
void
delete_cb
(
GtkWidget
*
button
,
GtkTreeSelection
*
sel
)
{
GtkTreeModel
*
model
;
GtkTreeIter
iter
;
GValue
val
;
struct
widget
*
w
;
gtk_tree_selection_get_selected
(
sel
,
&
model
,
&
iter
);
val
.
g_type
=
0
;
gtk_tree_model_get_value
(
model
,
&
iter
,
1
,
&
val
);
w
=
g_value_get_pointer
(
&
val
);
ap_widget_delete
(
w
);
gtk_list_store_remove
(
GTK_LIST_STORE
(
model
),
&
iter
);
}
static
void
rename_cb
(
GtkWidget
*
button
,
GtkTreeSelection
*
sel
)
{
GtkTreeModel
*
model
;
GtkTreeIter
iter
;
GValue
val
;
struct
widget
*
w
;
gtk_tree_selection_get_selected
(
sel
,
&
model
,
&
iter
);
val
.
g_type
=
0
;
gtk_tree_model_get_value
(
model
,
&
iter
,
1
,
&
val
);
w
=
g_value_get_pointer
(
&
val
);
purple_request_input
(
NULL
,
_
(
"Rename Widget"
),
NULL
,
_
(
"Enter a new name for this widget."
),
w
->
alias
,
FALSE
,
FALSE
,
NULL
,
_
(
"Rename"
),
G_CALLBACK
(
widget_popup_rename_cb
),
_
(
"Cancel"
),
NULL
,
NULL
,
NULL
,
NULL
,
w
);
}
static
void
add_cb
(
GtkWidget
*
button
,
GtkTreeSelection
*
sel
)
{
component_dialog_show
();
}
void
ap_widget_gtk_start
()
{
pref_names
=
g_hash_table_new
(
g_str_hash
,
g_str_equal
);
}
void
ap_widget_gtk_finish
()
{
done_with_widget_list
();
g_hash_table_destroy
(
pref_names
);
pref_names
=
NULL
;
}
static
void
widget_sel_cb
(
GtkTreeSelection
*
sel
,
GtkTreeModel
*
model
)
{
GtkTreeIter
iter
;
struct
widget
*
w
;
GValue
val
;
gtk_widget_destroy
(
dialog_box_contents
);
if
(
!
gtk_tree_selection_get_selected
(
sel
,
&
model
,
&
iter
))
{
gtk_widget_set_sensitive
(
rename_button
,
FALSE
);
gtk_widget_set_sensitive
(
delete_button
,
FALSE
);
dialog_box_contents
=
get_info_message
();
dialog_box_preview
=
NULL
;
dialog_box_widget
=
NULL
;
}
else
{
gtk_widget_set_sensitive
(
rename_button
,
TRUE
);
gtk_widget_set_sensitive
(
delete_button
,
TRUE
);
val
.
g_type
=
0
;
gtk_tree_model_get_value
(
GTK_TREE_MODEL
(
tree_list
),
&
iter
,
1
,
&
val
);
w
=
g_value_get_pointer
(
&
val
);
dialog_box_contents
=
get_widget_configuration
(
w
);
}
gtk_box_pack_start
(
GTK_BOX
(
dialog_box
),
dialog_box_contents
,
TRUE
,
TRUE
,
0
);
gtk_widget_show_all
(
dialog_box
);
}
GtkWidget
*
ap_widget_get_config_page
()
{
GtkTreeSelection
*
sel
;
GtkWidget
*
vbox
;
GtkWidget
*
add_button
;
/* Arrange main parts of window */
dialog_box
=
gtk_hbox_new
(
FALSE
,
0
);
vbox
=
gtk_vbox_new
(
FALSE
,
0
);
gtk_box_pack_start
(
GTK_BOX
(
dialog_box
),
vbox
,
FALSE
,
FALSE
,
0
);
get_widget_list
(
vbox
,
&
sel
);
g_signal_connect
(
G_OBJECT
(
sel
),
"changed"
,
G_CALLBACK
(
widget_sel_cb
),
NULL
);
add_button
=
gtk_button_new_with_label
(
_
(
"New Widget"
));
g_signal_connect
(
G_OBJECT
(
add_button
),
"clicked"
,
G_CALLBACK
(
add_cb
),
sel
);
gtk_box_pack_start
(
GTK_BOX
(
vbox
),
add_button
,
FALSE
,
FALSE
,
0
);
rename_button
=
gtk_button_new_with_label
(
_
(
"Rename"
));
gtk_widget_set_sensitive
(
rename_button
,
FALSE
);
g_signal_connect
(
G_OBJECT
(
rename_button
),
"clicked"
,
G_CALLBACK
(
rename_cb
),
sel
);
gtk_box_pack_start
(
GTK_BOX
(
vbox
),
rename_button
,
FALSE
,
FALSE
,
0
);
delete_button
=
gtk_button_new_with_label
(
_
(
"Delete"
));
gtk_widget_set_sensitive
(
delete_button
,
FALSE
);
g_signal_connect
(
G_OBJECT
(
delete_button
),
"clicked"
,
G_CALLBACK
(
delete_cb
),
sel
);
gtk_box_pack_start
(
GTK_BOX
(
vbox
),
delete_button
,
FALSE
,
FALSE
,
0
);
dialog_box_contents
=
get_info_message
();
gtk_box_pack_start
(
GTK_BOX
(
dialog_box
),
dialog_box_contents
,
TRUE
,
TRUE
,
0
);
return
dialog_box
;
}
/* DND */
static
void
drag_data_get_cb
(
GtkWidget
*
widget
,
GdkDragContext
*
ctx
,
GtkSelectionData
*
data
,
guint
info
,
guint
time
,
gpointer
user_data
)
{
GtkListStore
*
ls
=
(
GtkListStore
*
)
user_data
;
if
(
ls
==
NULL
)
return
;
if
(
data
->
target
==
gdk_atom_intern
(
"STRING"
,
FALSE
))
{
GtkTreeRowReference
*
ref
;
GtkTreePath
*
source_row
;
GtkTreeIter
iter
;
GString
*
s
;
struct
widget
*
w
;
GValue
val
=
{
0
};
ref
=
g_object_get_data
(
G_OBJECT
(
ctx
),
"gtk-tree-view-source-row"
);
source_row
=
gtk_tree_row_reference_get_path
(
ref
);
if
(
source_row
==
NULL
)
return
;
gtk_tree_model_get_iter
(
GTK_TREE_MODEL
(
ls
),
&
iter
,
source_row
);
gtk_tree_model_get_value
(
GTK_TREE_MODEL
(
ls
),
&
iter
,
1
,
&
val
);
w
=
g_value_get_pointer
(
&
val
);
s
=
g_string_new
(
""
);
g_string_printf
(
s
,
"[%s]"
,
w
->
alias
);
gtk_selection_data_set
(
data
,
gdk_atom_intern
(
"STRING"
,
FALSE
),
8
,
(
guchar
*
)
s
->
str
,
strlen
(
s
->
str
)
+
1
);
g_string_free
(
s
,
TRUE
);
gtk_tree_path_free
(
source_row
);
}
}
void
done_with_widget_list
()
{
if
(
tree_list
)
{
g_object_unref
(
tree_list
);
tree_list
=
NULL
;
}
widget_dialog
=
NULL
;
delete_button
=
NULL
;
dialog_box
=
NULL
;
dialog_box_contents
=
NULL
;
dialog_box_preview
=
NULL
;
dialog_box_widget
=
NULL
;
if
(
component_dialog
!=
NULL
)
{
gtk_widget_destroy
(
component_dialog
);
component_dialog
=
NULL
;
choose_button
=
NULL
;
}
}
GtkWidget
*
get_widget_list
(
GtkWidget
*
box
,
GtkTreeSelection
**
sel
)
{
GtkWidget
*
sw
;
GtkWidget
*
event_view
;
GtkCellRenderer
*
rend
;
GtkTreeViewColumn
*
col
;
GtkTargetEntry
gte
[]
=
{{
"STRING"
,
0
,
GTK_IMHTML_DRAG_STRING
}};
if
(
tree_list
==
NULL
)
{
tree_list
=
gtk_list_store_new
(
2
,
G_TYPE_STRING
,
G_TYPE_POINTER
);
gtk_tree_sortable_set_sort_column_id
(
GTK_TREE_SORTABLE
(
tree_list
),
0
,
GTK_SORT_ASCENDING
);
update_widget_list
(
tree_list
);
g_object_ref
(
G_OBJECT
(
tree_list
));
}
/* List of widgets */
sw
=
gtk_scrolled_window_new
(
NULL
,
NULL
);
gtk_scrolled_window_set_policy
(
GTK_SCROLLED_WINDOW
(
sw
),
GTK_POLICY_NEVER
,
GTK_POLICY_AUTOMATIC
);
gtk_scrolled_window_set_shadow_type
(
GTK_SCROLLED_WINDOW
(
sw
),
GTK_SHADOW_IN
);
gtk_box_pack_start
(
GTK_BOX
(
box
),
sw
,
TRUE
,
TRUE
,
0
);
event_view
=
gtk_tree_view_new_with_model
(
GTK_TREE_MODEL
(
tree_list
));
*
sel
=
gtk_tree_view_get_selection
(
GTK_TREE_VIEW
(
event_view
));
rend
=
gtk_cell_renderer_text_new
();
col
=
gtk_tree_view_column_new_with_attributes
(
_
(
"Widget"
),
rend
,
"markup"
,
0
,
NULL
);
gtk_tree_view_append_column
(
GTK_TREE_VIEW
(
event_view
),
col
);
gtk_tree_view_column_set_sort_column_id
(
col
,
0
);
gtk_container_add
(
GTK_CONTAINER
(
sw
),
event_view
);
/* Drag and Drop */
gtk_tree_view_enable_model_drag_source
(
GTK_TREE_VIEW
(
event_view
),
GDK_BUTTON1_MASK
,
gte
,
1
,
GDK_ACTION_COPY
);
g_signal_connect
(
G_OBJECT
(
event_view
),
"drag-data-get"
,
G_CALLBACK
(
drag_data_get_cb
),
tree_list
);
return
event_view
;
}
/*********************************************************
Component selection window
**********************************************************/
static
void
add_component
(
struct
component
*
c
)
{
struct
widget
*
w
;
GtkTreeIter
iter
;
GString
*
s
;
w
=
ap_widget_create
(
c
);
if
(
w
==
NULL
)
return
;
s
=
g_string_new
(
""
);
gtk_list_store_append
(
tree_list
,
&
iter
);
g_string_printf
(
s
,
"<b>%s</b>"
,
w
->
alias
);
gtk_list_store_set
(
tree_list
,
&
iter
,
0
,
s
->
str
,
1
,
w
,
-1
);
g_string_free
(
s
,
TRUE
);
}
static
void
component_row_activate_cb
(
GtkTreeView
*
view
,
GtkTreePath
*
path
,
GtkTreeViewColumn
*
column
,
gpointer
null
)
{
GtkTreeSelection
*
sel
;
GtkTreeIter
iter
;
struct
component
*
c
;
GtkTreeModel
*
model
;
sel
=
gtk_tree_view_get_selection
(
view
);
if
(
gtk_tree_selection_get_selected
(
sel
,
&
model
,
&
iter
))
{
gtk_tree_model_get
(
model
,
&
iter
,
1
,
&
c
,
-1
);
add_component
(
c
);
}
gtk_widget_destroy
(
component_dialog
);
component_dialog
=
NULL
;
choose_button
=
NULL
;
}
static
void
component_response_cb
(
GtkWidget
*
d
,
int
response
,
GtkTreeSelection
*
sel
)
{
GtkTreeModel
*
model
;
GtkTreeIter
iter
;
GValue
val
;
struct
component
*
c
;
switch
(
response
)
{
case
AP_RESPONSE_CHOOSE
:
gtk_tree_selection_get_selected
(
sel
,
&
model
,
&
iter
);
val
.
g_type
=
0
;
gtk_tree_model_get_value
(
model
,
&
iter
,
1
,
&
val
);
c
=
g_value_get_pointer
(
&
val
);
add_component
(
c
);
case
GTK_RESPONSE_CLOSE
:
case
GTK_RESPONSE_CANCEL
:
case
GTK_RESPONSE_DELETE_EVENT
:
gtk_widget_destroy
(
d
);
component_dialog
=
NULL
;
choose_button
=
NULL
;
break
;
}
}
static
void
component_sel_cb
(
GtkTreeSelection
*
sel
,
GtkTreeModel
*
model
)
{
GtkTreeIter
iter
;
if
(
!
gtk_tree_selection_get_selected
(
sel
,
&
model
,
&
iter
))
{
gtk_widget_set_sensitive
(
choose_button
,
FALSE
);
}
else
{
gtk_widget_set_sensitive
(
choose_button
,
TRUE
);
}
}
static
void
update_component_list
(
GtkListStore
*
ls
)
{
GtkTreeIter
iter
;
GList
*
components
;
struct
component
*
c
;
GString
*
s
;
gchar
*
name
,
*
description
;
gtk_list_store_clear
(
ls
);
s
=
g_string_new
(
""
);
for
(
components
=
ap_component_get_components
();
components
!=
NULL
;
components
=
components
->
next
)
{
gtk_list_store_append
(
ls
,
&
iter
);
c
=
(
struct
component
*
)
components
->
data
;
name
=
g_markup_escape_text
(
c
->
name
,
-1
);
description
=
g_markup_escape_text
(
c
->
description
,
-1
);
g_string_printf
(
s
,
"<b>%s</b>
\n
%s"
,
name
,
description
);
gtk_list_store_set
(
ls
,
&
iter
,
0
,
s
->
str
,
1
,
c
,
-1
);
free
(
name
);
free
(
description
);
}
g_string_free
(
s
,
TRUE
);
}
static
void
component_dialog_show
()
{
GtkWidget
*
sw
;
GtkWidget
*
event_view
;
GtkListStore
*
ls
;
GtkCellRenderer
*
rendt
;
GtkTreeViewColumn
*
col
;
GtkTreeSelection
*
sel
;
if
(
component_dialog
!=
NULL
)
{
gtk_window_present
(
GTK_WINDOW
(
component_dialog
));
return
;
}
component_dialog
=
gtk_dialog_new_with_buttons
(
_
(
"Select a widget type"
),
NULL
,
GTK_DIALOG_NO_SEPARATOR
,
NULL
);
choose_button
=
gtk_dialog_add_button
(
GTK_DIALOG
(
component_dialog
),
_
(
"Create widget"
),
AP_RESPONSE_CHOOSE
);
gtk_dialog_add_button
(
GTK_DIALOG
(
component_dialog
),
GTK_STOCK_CANCEL
,
GTK_RESPONSE_CANCEL
);
gtk_widget_set_sensitive
(
choose_button
,
FALSE
);
sw
=
gtk_scrolled_window_new
(
NULL
,
NULL
);
gtk_scrolled_window_set_policy
(
GTK_SCROLLED_WINDOW
(
sw
),
GTK_POLICY_AUTOMATIC
,
GTK_POLICY_ALWAYS
);
gtk_scrolled_window_set_shadow_type
(
GTK_SCROLLED_WINDOW
(
sw
),
GTK_SHADOW_IN
);
gtk_box_pack_start
(
GTK_BOX
(
GTK_DIALOG
(
component_dialog
)
->
vbox
),
sw
,
TRUE
,
TRUE
,
0
);
ls
=
gtk_list_store_new
(
2
,
G_TYPE_STRING
,
G_TYPE_POINTER
);
gtk_tree_sortable_set_sort_column_id
(
GTK_TREE_SORTABLE
(
ls
),
0
,
GTK_SORT_ASCENDING
);
update_component_list
(
ls
);
event_view
=
gtk_tree_view_new_with_model
(
GTK_TREE_MODEL
(
ls
));
g_signal_connect
(
G_OBJECT
(
event_view
),
"row-activated"
,
G_CALLBACK
(
component_row_activate_cb
),
event_view
);
sel
=
gtk_tree_view_get_selection
(
GTK_TREE_VIEW
(
event_view
));
rendt
=
gtk_cell_renderer_text_new
();
col
=
gtk_tree_view_column_new_with_attributes
(
_
(
"Widget type"
),
rendt
,
"markup"
,
0
,
NULL
);
#if GTK_CHECK_VERSION(2,6,0)
gtk_tree_view_column_set_expand
(
col
,
TRUE
);
g_object_set
(
rendt
,
"ellipsize"
,
PANGO_ELLIPSIZE_END
,
NULL
);
#endif
gtk_tree_view_append_column
(
GTK_TREE_VIEW
(
event_view
),
col
);
gtk_tree_view_column_set_sort_column_id
(
col
,
0
);
g_object_unref
(
G_OBJECT
(
ls
));
gtk_container_add
(
GTK_CONTAINER
(
sw
),
event_view
);
g_signal_connect
(
G_OBJECT
(
sel
),
"changed"
,
G_CALLBACK
(
component_sel_cb
),
NULL
);
g_signal_connect
(
G_OBJECT
(
component_dialog
),
"response"
,
G_CALLBACK
(
component_response_cb
),
sel
);
gtk_window_set_default_size
(
GTK_WINDOW
(
component_dialog
),
550
,
430
);
gtk_widget_show_all
(
component_dialog
);
}
/* Preferences stuff */
static
void
pref_callback
(
const
char
*
name
,
PurplePrefType
type
,
gconstpointer
val
,
gpointer
data
)
{
struct
widget
*
w
=
(
struct
widget
*
)
data
;
ap_widget_prefs_updated
(
w
);
}
static
const
gchar
*
get_const_pref
(
struct
widget
*
w
,
const
char
*
key
)
{
gchar
*
pref
,
*
result
;
// This is here to prevent memory leaks
pref
=
ap_prefs_get_pref_name
(
w
,
key
);
if
(
pref_names
==
NULL
)
{
pref_names
=
g_hash_table_new
(
g_str_hash
,
g_str_equal
);
}
result
=
g_hash_table_lookup
(
pref_names
,
pref
);
if
(
!
result
)
{
g_hash_table_insert
(
pref_names
,
pref
,
pref
);
return
pref
;
}
else
{
free
(
pref
);
return
result
;
}
}
GtkWidget
*
ap_prefs_checkbox
(
struct
widget
*
w
,
const
char
*
title
,
const
char
*
key
,
GtkWidget
*
page
)
{
GtkWidget
*
result
;
const
gchar
*
pref
;
pref
=
get_const_pref
(
w
,
key
);
result
=
pidgin_prefs_checkbox
(
title
,
pref
,
page
);
purple_prefs_connect_callback
(
ap_get_plugin_handle
(),
pref
,
pref_callback
,
w
);
return
result
;
}
GtkWidget
*
ap_prefs_dropdown_from_list
(
struct
widget
*
w
,
GtkWidget
*
page
,
const
gchar
*
title
,
PurplePrefType
type
,
const
char
*
key
,
GList
*
menuitems
)
{
GtkWidget
*
result
;
const
gchar
*
pref
;
pref
=
get_const_pref
(
w
,
key
);
result
=
pidgin_prefs_dropdown_from_list
(
page
,
title
,
type
,
pref
,
menuitems
);
purple_prefs_connect_callback
(
ap_get_plugin_handle
(),
pref
,
pref_callback
,
w
);
return
result
;
}
GtkWidget
*
ap_prefs_labeled_entry
(
struct
widget
*
w
,
GtkWidget
*
page
,
const
gchar
*
title
,
const
char
*
key
,
GtkSizeGroup
*
sg
)
{
GtkWidget
*
result
;
const
gchar
*
pref
;
pref
=
get_const_pref
(
w
,
key
);
result
=
pidgin_prefs_labeled_entry
(
page
,
title
,
pref
,
sg
);
purple_prefs_connect_callback
(
ap_get_plugin_handle
(),
pref
,
pref_callback
,
w
);
return
result
;
}
GtkWidget
*
ap_prefs_labeled_spin_button
(
struct
widget
*
w
,
GtkWidget
*
page
,
const
gchar
*
title
,
const
char
*
key
,
int
min
,
int
max
,
GtkSizeGroup
*
sg
)
{
GtkWidget
*
result
;
const
gchar
*
pref
;
pref
=
get_const_pref
(
w
,
key
);
result
=
pidgin_prefs_labeled_spin_button
(
page
,
title
,
pref
,
min
,
max
,
sg
);
purple_prefs_connect_callback
(
ap_get_plugin_handle
(),
pref
,
pref_callback
,
w
);
return
result
;
}