* Screen Capture - a plugin that allows taking screenshots and sending them
* to your buddies as inline images.
* Copyright (C) 2014, Tomasz Wasilczyk <twasilczyk@pidgin.im>
* 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 <gdk/gdkkeysyms.h>
#include "gtkwebviewtoolbar.h"
#define SCRNCAP_SHOOTING_TIMEOUT 500
#define SCRNCAP_DEFAULT_COLOR "#FFFF00000000"
static gboolean is_shooting = FALSE;
static guint shooting_timeout = 0;
static GtkWidget *current_window = NULL;
static gint crop_origin_x, crop_origin_y;
static gboolean crop_active;
static gint crop_x, crop_y, crop_w, crop_h;
static gint draw_origin_x, draw_origin_y;
static gboolean draw_active;
static GdkRGBA brush_color = {1, 0, 0, 1};
static gint line_width = 2;
/******************************************************************************
* libpidgin helper functions
******************************************************************************/
scrncap_conv_set_data(PidginConversation *gtkconv, const gchar *key,
g_return_if_fail(gtkconv != NULL);
g_object_set_data(G_OBJECT(gtkconv->tab_cont), key, value);
scrncap_conv_get_data(PidginConversation *gtkconv, const gchar *key)
g_return_val_if_fail(gtkconv != NULL, NULL);
return g_object_get_data(G_OBJECT(gtkconv->tab_cont), key);
/******************************************************************************
* GdkPixbuf helper functions
******************************************************************************/
scrncap_perform_screenshot(void)
root = gdk_get_default_root_window();
gdk_window_get_origin(root, &orig_x, &orig_y);
return gdk_pixbuf_get_from_window(root, 0, 0,
gdk_window_get_width(root), gdk_window_get_height(root));
scrncap_pixbuf_darken(GdkPixbuf *pixbuf)
int i, y, width, height, row_width, n_channels, rowstride, pad;
pixels = gdk_pixbuf_get_pixels(pixbuf);
width = gdk_pixbuf_get_width(pixbuf);
height = gdk_pixbuf_get_height(pixbuf);
n_channels = gdk_pixbuf_get_n_channels(pixbuf);
rowstride = gdk_pixbuf_get_rowstride(pixbuf);
row_width = width * n_channels;
pad = rowstride - row_width;
g_return_if_fail(pad >= 0);
for (y = 0; y < height; y++) {
for (i = 0; i < row_width; i++, pixels++)
scrncap_pixbuf_to_image(GdkPixbuf *pixbuf)
PurpleImage *image = NULL;
if (!gdk_pixbuf_save_to_buffer(pixbuf, &buffer, &count, "png",
purple_debug_error("screencap", "Failed saving an image: %s",
image = purple_image_new_take_data((guint8 *)buffer, count);
if (purple_image_get_extension(image) == NULL) {
purple_debug_error("screencap", "Invalid image format");
/******************************************************************************
******************************************************************************/
scrncap_drawing_area_btnpress(GtkWidget *draw_area, GdkEventButton *event,
draw_origin_x = event->x;
draw_origin_y = event->y;
scrncap_drawing_area_btnrelease(GtkWidget *draw_area, GdkEvent *event,
scrncap_drawing_area_motion(GtkWidget *draw_area, GdkEventButton *event,
int redraw_x, redraw_y, redraw_w, redraw_h;
cairo_move_to(cr, draw_origin_x, draw_origin_y);
cairo_set_line_width(cr, line_width);
redraw_x = MIN(draw_origin_x, x) - line_width - 1;
redraw_y = MIN(draw_origin_y, y) - line_width - 1;
redraw_w = MAX(draw_origin_x, x) - redraw_x + line_width + 1;
redraw_h = MAX(draw_origin_y, y) - redraw_y + line_width + 1;
gtk_widget_queue_draw_area(draw_area,
redraw_x, redraw_y, redraw_w, redraw_h);
scrncap_drawing_area_enter(GtkWidget *widget, GdkEvent *event,
gdkwindow = gtk_widget_get_window(GTK_WIDGET(widget));
gdk_window_set_cursor(gdkwindow, draw_cursor);
scrncap_drawing_area_leave(GtkWidget *widget, GdkEvent *event,
gdkwindow = gtk_widget_get_window(GTK_WIDGET(widget));
gdk_window_set_cursor(gdkwindow, NULL);
scrncap_draw_window_close(GtkWidget *window, gpointer _unused)
if (current_window != window)
scrncap_draw_window_paint(GtkWidget *widget, cairo_t *cr, gpointer _surface)
cairo_surface_t *surface = _surface;
cairo_set_source_surface(cr, surface, 0, 0);
scrncap_draw_window_response(GtkDialog *draw_window, gint response_id,
PidginWebView *webview = PIDGIN_WEBVIEW(_webview);
GdkPixbuf *result = NULL;
const gchar *fname_prefix;
static guint fname_no = 0;
if (response_id == SCRNCAP_RESPONSE_COLOR)
if (response_id == GTK_RESPONSE_OK) {
cairo_surface_t *surface = g_object_get_data(
G_OBJECT(draw_window), "surface");
result = gdk_pixbuf_get_from_surface(surface, 0, 0,
cairo_image_surface_get_width(surface),
cairo_image_surface_get_height(surface));
gtk_widget_destroy(GTK_WIDGET(draw_window));
image = scrncap_pixbuf_to_image(result);
/* translators: this is the file name prefix,
* keep it lowercase and pure ASCII.
* Please avoid "_" character, use "-" instead. */
fname_prefix = _("screenshot-");
fname = g_strdup_printf("%s%u", fname_prefix, ++fname_no);
purple_image_set_friendly_filename(image, fname);
pidgin_webview_insert_image(webview, image);
scrncap_draw_color_selected(GtkColorButton *button, cairo_t *cr)
gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(button), &brush_color);
gdk_cairo_set_source_rgba(cr, &brush_color);
color_str = gdk_rgba_to_string(&brush_color);
purple_prefs_set_string("/plugins/gtk/screencap/brush_color", color_str);
scrncap_draw_window(PidginWebView *webview, GdkPixbuf *screen)
GtkWidget *drawing_area, *box;
cairo_surface_t *surface;
current_window = pidgin_create_dialog(
_("Insert screenshot"), 0, "insert-screenshot", TRUE);
draw_window = GTK_DIALOG(current_window);
gtk_widget_set_size_request(GTK_WIDGET(draw_window), 400, 300);
gtk_window_set_position(GTK_WINDOW(draw_window), GTK_WIN_POS_CENTER);
g_signal_connect(G_OBJECT(draw_window), "destroy",
G_CALLBACK(scrncap_draw_window_close), NULL);
display = gtk_widget_get_display(current_window);
draw_cursor = gdk_cursor_new_for_display(display, GDK_PENCIL);
g_object_set_data_full(G_OBJECT(draw_window), "draw-cursor",
draw_cursor, g_object_unref);
width = gdk_pixbuf_get_width(screen);
height = gdk_pixbuf_get_height(screen);
surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
cr = cairo_create(surface);
g_signal_connect_swapped(G_OBJECT(draw_window), "destroy",
G_CALLBACK(cairo_destroy), cr);
g_object_set_data_full(G_OBJECT(draw_window), "surface",
surface, (GDestroyNotify)cairo_surface_destroy);
gdk_cairo_set_source_pixbuf(cr, screen, 0, 0);
cairo_rectangle(cr, 0, 0, width, height);
drawing_area = gtk_drawing_area_new();
gtk_widget_set_size_request(drawing_area, width, height);
g_signal_connect(G_OBJECT(drawing_area), "draw",
G_CALLBACK(scrncap_draw_window_paint), surface);
gtk_widget_add_events(drawing_area, GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_MOTION_MASK |
GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
g_signal_connect(G_OBJECT(drawing_area), "button-press-event",
G_CALLBACK(scrncap_drawing_area_btnpress), NULL);
g_signal_connect(G_OBJECT(drawing_area), "button-release-event",
G_CALLBACK(scrncap_drawing_area_btnrelease), NULL);
g_signal_connect(G_OBJECT(drawing_area), "motion-notify-event",
G_CALLBACK(scrncap_drawing_area_motion), cr);
g_signal_connect(G_OBJECT(drawing_area), "enter-notify-event",
G_CALLBACK(scrncap_drawing_area_enter), draw_cursor);
g_signal_connect(G_OBJECT(drawing_area), "leave-notify-event",
G_CALLBACK(scrncap_drawing_area_leave), draw_cursor);
g_object_set(drawing_area,
"halign", GTK_ALIGN_CENTER,
"valign", GTK_ALIGN_CENTER,
scroll_area = pidgin_make_scrollable(box,
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC,
GTK_SHADOW_NONE, -1, -1);
g_object_set(G_OBJECT(scroll_area), "expand", TRUE, NULL);
gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(
GTK_DIALOG(draw_window))), scroll_area);
color_button = gtk_color_button_new();
gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(color_button),
g_signal_connect(G_OBJECT(color_button), "color-set",
G_CALLBACK(scrncap_draw_color_selected), cr);
scrncap_draw_color_selected(GTK_COLOR_BUTTON(color_button), cr);
gtk_dialog_add_action_widget(draw_window, color_button,
gtk_dialog_add_button(draw_window, _("_Add"), GTK_RESPONSE_OK);
gtk_dialog_add_button(draw_window, _("_Cancel"),
gtk_dialog_set_default_response(draw_window, GTK_RESPONSE_OK);
g_signal_connect(G_OBJECT(draw_window), "response",
G_CALLBACK(scrncap_draw_window_response), webview);
gtk_widget_show_all(GTK_WIDGET(draw_window));
/******************************************************************************
******************************************************************************/
scrncap_crop_window_close(GtkWidget *window, gpointer _unused)
if (current_window != window)
scrncap_crop_window_keypress(GtkWidget *crop_window, GdkEventKey *event,
PidginWebView *webview = PIDGIN_WEBVIEW(_webview);
guint key = event->keyval;
if (key == GDK_KEY_Escape) {
gtk_widget_destroy(crop_window);
if (key == GDK_KEY_Return) {
GdkPixbuf *screenshot, *subscreen, *result;
screenshot = g_object_get_data(G_OBJECT(crop_window),
subscreen = gdk_pixbuf_new_subpixbuf(screenshot,
crop_x, crop_y, crop_w, crop_h);
result = gdk_pixbuf_copy(subscreen);
g_object_unref(subscreen);
gtk_widget_destroy(crop_window);
scrncap_draw_window(webview, result);
scrncap_crop_window_focusout(GtkWidget *window, GdkEventFocus *event,
gtk_widget_destroy(window);
scrncap_crop_window_btnpress(GtkWidget *window, GdkEventButton *event,
g_return_val_if_fail(!crop_active, TRUE);
hint_box = g_object_get_data(G_OBJECT(window), "hint-box");
gtk_widget_destroy(hint_box);
g_object_set_data(G_OBJECT(window), "hint-box", NULL);
selection = g_object_get_data(G_OBJECT(window), "selection");
cont = g_object_get_data(G_OBJECT(window), "cont");
gtk_fixed_move(cont, GTK_WIDGET(selection), -10, -10);
gtk_image_set_from_pixbuf(selection, NULL);
gtk_widget_show(GTK_WIDGET(selection));
crop_origin_x = event->x_root;
crop_origin_y = event->y_root;
scrncap_crop_window_btnrelease(GtkWidget *window, GdkEvent *event,
scrncap_crop_window_motion(GtkWidget *window, GdkEventButton *event,
GdkPixbuf *crop, *screenshot;
g_return_val_if_fail(crop_active, FALSE);
selection = g_object_get_data(G_OBJECT(window), "selection");
cont = g_object_get_data(G_OBJECT(window), "cont");
crop_x = MIN(crop_origin_x, event->x_root);
crop_y = MIN(crop_origin_y, event->y_root);
crop_w = abs(crop_origin_x - event->x_root);
crop_h = abs(crop_origin_y - event->y_root);
gtk_fixed_move(cont, GTK_WIDGET(selection), crop_x, crop_y);
screenshot = g_object_get_data(G_OBJECT(window), "screenshot");
crop = gdk_pixbuf_new_subpixbuf(screenshot,
crop_x, crop_y, crop_w, crop_h);
gtk_image_set_from_pixbuf(GTK_IMAGE(selection), crop);
scrncap_crop_window_realize(GtkWidget *crop_window, gpointer _unused)
gdkwindow = gtk_widget_get_window(GTK_WIDGET(crop_window));
display = gdk_window_get_display(gdkwindow);
gdk_window_set_events(gdkwindow, gdk_window_get_events(gdkwindow) |
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
cursor = gdk_cursor_new_for_display(display, GDK_CROSSHAIR);
gdk_window_set_cursor(gdkwindow, cursor);
scrncap_do_screenshot_cb(gpointer _webview)
PidginWebView *webview = PIDGIN_WEBVIEW(_webview);
GdkPixbuf *screenshot, *screenshot_d;
GtkImage *image, *selection;
GtkRequisition hint_size;
screenshot = scrncap_perform_screenshot();
g_return_val_if_fail(screenshot != NULL, G_SOURCE_REMOVE);
width = gdk_pixbuf_get_width(screenshot);
height = gdk_pixbuf_get_height(screenshot);
current_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
crop_window = GTK_WINDOW(current_window);
gtk_window_set_decorated(crop_window, FALSE);
gtk_window_set_resizable(crop_window, FALSE);
gtk_widget_set_size_request(GTK_WIDGET(crop_window), width, height);
gtk_window_fullscreen(crop_window);
gtk_window_set_keep_above(crop_window, TRUE);
g_signal_connect(G_OBJECT(crop_window), "realize",
G_CALLBACK(scrncap_crop_window_realize), NULL);
g_signal_connect(G_OBJECT(crop_window), "destroy",
G_CALLBACK(scrncap_crop_window_close), NULL);
g_signal_connect(G_OBJECT(crop_window), "key-press-event",
G_CALLBACK(scrncap_crop_window_keypress), webview);
g_signal_connect(G_OBJECT(crop_window), "focus-out-event",
G_CALLBACK(scrncap_crop_window_focusout), NULL);
g_signal_connect(G_OBJECT(crop_window), "button-press-event",
G_CALLBACK(scrncap_crop_window_btnpress), NULL);
g_signal_connect(G_OBJECT(crop_window), "button-release-event",
G_CALLBACK(scrncap_crop_window_btnrelease), NULL);
g_signal_connect(G_OBJECT(crop_window), "motion-notify-event",
G_CALLBACK(scrncap_crop_window_motion), NULL);
g_object_set_data_full(G_OBJECT(crop_window), "screenshot",
screenshot, g_object_unref);
cont = GTK_FIXED(gtk_fixed_new());
g_object_set_data(G_OBJECT(crop_window), "cont", cont);
gtk_container_add(GTK_CONTAINER(crop_window), GTK_WIDGET(cont));
screenshot_d = gdk_pixbuf_copy(screenshot);
scrncap_pixbuf_darken(screenshot_d);
image = GTK_IMAGE(gtk_image_new_from_pixbuf(screenshot_d));
g_object_unref(screenshot_d);
gtk_fixed_put(cont, GTK_WIDGET(image), 0, 0);
selection = GTK_IMAGE(gtk_image_new_from_pixbuf(NULL));
gtk_fixed_put(cont, GTK_WIDGET(selection), -10, -10);
g_object_set_data(G_OBJECT(crop_window), "selection", selection);
hint = gtk_label_new(NULL);
hint_msg = g_strdup_printf("<span size='x-large'>%s</span>",
_("Select the region to send and press Enter button to confirm "
"or press Escape button to cancel"));
gtk_label_set_markup(GTK_LABEL(hint), hint_msg);
gtk_widget_set_margin_start(hint, 10);
gtk_widget_set_margin_end(hint, 10);
gtk_widget_set_margin_top(hint, 7);
gtk_widget_set_margin_bottom(hint, 7);
hint_box = gtk_event_box_new();
gtk_container_add(GTK_CONTAINER(hint_box), hint);
gtk_widget_get_preferred_size(hint, NULL, &hint_size);
gtk_fixed_put(cont, hint_box,
width / 2 - hint_size.width / 2 - 10,
height / 2 - hint_size.height / 2 - 7);
g_object_set_data(G_OBJECT(crop_window), "hint-box", hint_box);
gtk_widget_show_all(GTK_WIDGET(crop_window));
gtk_widget_hide(GTK_WIDGET(selection));
scrncap_do_screenshot(GtkAction *action, PidginWebView *webview)
gtk_window_present(GTK_WINDOW(current_window));
shooting_timeout = g_timeout_add(SCRNCAP_SHOOTING_TIMEOUT,
scrncap_do_screenshot_cb, webview);
/******************************************************************************
* PidginConversation setup
******************************************************************************/
scrncap_convwin_switch(GtkNotebook *notebook, GtkWidget *page, gint page_num,
PidginConvWindow *win = _win;
PidginConversation *gtkconv;
gboolean images_supported;
gtkconv = pidgin_conv_window_get_active_gtkconv(win);
webview = PIDGIN_WEBVIEW(gtkconv->entry);
action = g_object_get_data(G_OBJECT(win->menu->menubar),
"insert-screenshot-action");
g_return_if_fail(action != NULL);
images_supported = pidgin_webview_get_format_functions(webview) &
gtk_action_set_sensitive(action, images_supported);
scrncap_convwin_menu_cb(GtkAction *action, PidginConvWindow *win)
PidginConversation *gtkconv;
gtkconv = pidgin_conv_window_get_active_gtkconv(win);
webview = PIDGIN_WEBVIEW(gtkconv->entry);
scrncap_do_screenshot(action, webview);
scrncap_convwin_init(PidginConvWindow *win)
PidginConvWindowMenu *menu = win->menu;
GtkWidget *conv_submenu, *conv_insert_image;
GtkWidget *scrncap_btn_menu;
action = g_object_get_data(G_OBJECT(menu->menubar),
"insert-screenshot-action");
action = gtk_action_new("InsertScreenshot", _("Insert Screens_hot..."),
NULL, PIDGIN_ICON_CAMERA_PHOTO);
gtk_action_set_is_important(action, TRUE);
g_object_set_data_full(G_OBJECT(menu->menubar),
"insert-screenshot-action", action, g_object_unref);
g_signal_connect(G_OBJECT(action), "activate",
G_CALLBACK(scrncap_convwin_menu_cb), win);
conv_insert_image = gtk_ui_manager_get_widget(menu->ui,
"/Conversation/ConversationMenu/InsertImage");
g_return_if_fail(conv_insert_image != NULL);
conv_submenu = gtk_widget_get_parent(conv_insert_image);
children = gtk_container_get_children(GTK_CONTAINER(conv_submenu));
pos = g_list_index(children, conv_insert_image);
g_warn_if_fail(pos >= 0);
scrncap_btn_menu = gtk_action_create_menu_item(action);
g_object_set_data(G_OBJECT(menu->menubar), "insert-screenshot-btn",
gtk_menu_shell_insert(GTK_MENU_SHELL(conv_submenu),
GTK_WIDGET(scrncap_btn_menu), pos);
gtk_widget_show(GTK_WIDGET(scrncap_btn_menu));
g_signal_connect_after(G_OBJECT(win->notebook), "switch-page",
G_CALLBACK(scrncap_convwin_switch), win);
scrncap_convwin_switch(GTK_NOTEBOOK(win->notebook), NULL, 0, win);
scrncap_convwin_uninit(PidginConvWindow *win)
PidginConvWindowMenu *menu = win->menu;
btn = g_object_get_data(G_OBJECT(menu->menubar),
"insert-screenshot-btn");
g_object_set_data(G_OBJECT(menu->menubar),
"insert-screenshot-btn", NULL);
g_object_set_data(G_OBJECT(menu->menubar),
"insert-screenshot-action", NULL);
g_signal_handlers_disconnect_matched(win->notebook, G_SIGNAL_MATCH_FUNC,
0, 0, NULL, scrncap_convwin_switch, NULL);
scrncap_conversation_update(PidginWebView *webview,
PidginWebViewButtons buttons, gpointer _action)
GtkAction *action = GTK_ACTION(_action);
gtk_action_set_sensitive(action, buttons & PIDGIN_WEBVIEW_IMAGE);
scrncap_conversation_init(PidginConversation *gtkconv)
PidginWebViewToolbar *toolbar;
GtkToolItem *scrncap_btn_wide;
GtkWidget *scrncap_btn_lean;
GtkToolbar *wide_view, *lean_view;
GtkMenu *wide_menu = NULL;
GList *wide_children, *it;
if (scrncap_conv_get_data(gtkconv, "scrncap-btn-wide") != NULL)
webview = PIDGIN_WEBVIEW(gtkconv->entry);
toolbar = PIDGIN_WEBVIEWTOOLBAR(pidgin_webview_get_toolbar(webview));
g_return_if_fail(toolbar != NULL);
wide_view = GTK_TOOLBAR(pidgin_webviewtoolbar_get_wide_view(toolbar));
g_return_if_fail(wide_view != NULL);
lean_view = GTK_TOOLBAR(pidgin_webviewtoolbar_get_lean_view(toolbar));
g_return_if_fail(lean_view != NULL);
action = gtk_action_new("InsertScreenshot", _("_Screenshot"),
_("Insert screenshot"), PIDGIN_ICON_CAMERA_PHOTO);
gtk_action_set_is_important(action, TRUE);
g_signal_connect(G_OBJECT(action), "activate",
G_CALLBACK(scrncap_do_screenshot), webview);
scrncap_btn_wide = GTK_TOOL_ITEM(gtk_action_create_tool_item(action));
scrncap_conv_set_data(gtkconv, "scrncap-btn-wide", scrncap_btn_wide);
for (i = 0; i < gtk_toolbar_get_n_items(wide_view); i++) {
GtkToolItem *ref_item = gtk_toolbar_get_nth_item(wide_view, i);
action = g_object_get_data(G_OBJECT(ref_item), "action");
if (g_strcmp0(gtk_action_get_name(action), "InsertImage") == 0) {
gtk_toolbar_insert(wide_view, scrncap_btn_wide, pos);
gtk_widget_show(GTK_WIDGET(scrncap_btn_wide));
for (i = 0; i < gtk_toolbar_get_n_items(lean_view); i++) {
GtkToolItem *ref_item = gtk_toolbar_get_nth_item(lean_view, i);
menu_name = g_object_get_data(G_OBJECT(ref_item), "menu-name");
if (g_strcmp0(menu_name, "insert") == 0) {
wide_menu = g_object_get_data(G_OBJECT(ref_item), "menu");
g_return_if_fail(wide_menu);
wide_children = gtk_container_get_children(GTK_CONTAINER(wide_menu));
for (it = wide_children, i = 0; it; it = g_list_next(it), i++) {
GtkWidget *child = it->data;
action = g_object_get_data(G_OBJECT(child), "action");
if (g_strcmp0(gtk_action_get_name(action), "InsertImage") == 0) {
g_list_free(wide_children);
g_warn_if_fail(pos >= 0);
g_signal_connect_object(G_OBJECT(webview), "allowed-formats-updated",
G_CALLBACK(scrncap_conversation_update), action, 0);
scrncap_conversation_update(webview,
pidgin_webview_get_format_functions(webview), action);
scrncap_btn_lean = gtk_action_create_menu_item(action);
scrncap_conv_set_data(gtkconv, "scrncap-btn-lean", scrncap_btn_lean);
gtk_menu_shell_insert(GTK_MENU_SHELL(wide_menu),
GTK_WIDGET(scrncap_btn_lean), pos);
gtk_widget_show(GTK_WIDGET(scrncap_btn_lean));
scrncap_conversation_uninit(PidginConversation *gtkconv)
GtkWidget *scrncap_btn_wide, *scrncap_btn_lean;
scrncap_btn_wide = scrncap_conv_get_data(gtkconv, "scrncap-btn-wide");
if (scrncap_btn_wide == NULL)
scrncap_btn_lean = scrncap_conv_get_data(gtkconv, "scrncap-btn-lean");
gtk_widget_destroy(scrncap_btn_wide);
gtk_widget_destroy(scrncap_btn_lean);
scrncap_conv_set_data(gtkconv, "scrncap-btn-wide", NULL);
scrncap_conv_set_data(gtkconv, "scrncap-btn-lean", NULL);
/******************************************************************************
******************************************************************************/
static PidginPluginInfo *
plugin_query(GError **error)
const gchar * const authors[] = {
"Tomasz Wasilczyk <twasilczyk@pidgin.im>",
return pidgin_plugin_info_new(
"name", N_("Screen Capture"),
"version", DISPLAY_VERSION,
"category", N_("Utility"),
"summary", N_("Send screenshots to your buddies."),
"description", N_("Adds an option to send a screenshot as an inline "
"image. It works only with protocols that supports "
"website", PURPLE_WEBSITE,
"abi-version", PURPLE_ABI_VERSION,
plugin_load(PurplePlugin *plugin, GError **error)
purple_prefs_add_none("/plugins");
purple_prefs_add_none("/plugins/gtk");
purple_prefs_add_none("/plugins/gtk/screencap");
purple_prefs_add_string("/plugins/gtk/screencap/brush_color",
color_str = purple_prefs_get_string("/plugins/gtk/screencap/brush_color");
if (color_str && color_str[0])
gdk_rgba_parse(&brush_color, color_str);
purple_signal_connect(pidgin_conversations_get_handle(),
"conversation-displayed", plugin,
PURPLE_CALLBACK(scrncap_conversation_init), NULL);
purple_signal_connect(pidgin_conversations_get_handle(),
"conversation-window-created", plugin,
PURPLE_CALLBACK(scrncap_convwin_init), NULL);
it = purple_conversations_get_all();
for (; it; it = g_list_next(it)) {
PurpleConversation *conv = it->data;
if (!PIDGIN_IS_PIDGIN_CONVERSATION(conv))
scrncap_conversation_init(PIDGIN_CONVERSATION(conv));
it = pidgin_conv_windows_get_list();
for (; it; it = g_list_next(it)) {
PidginConvWindow *win = it->data;
scrncap_convwin_init(win);
plugin_unload(PurplePlugin *plugin, GError **error)
if (shooting_timeout > 0)
g_source_remove(shooting_timeout);
if (current_window != NULL)
gtk_widget_destroy(GTK_WIDGET(current_window));
it = purple_conversations_get_all();
for (; it; it = g_list_next(it)) {
PurpleConversation *conv = it->data;
if (!PIDGIN_IS_PIDGIN_CONVERSATION(conv))
scrncap_conversation_uninit(PIDGIN_CONVERSATION(conv));
it = pidgin_conv_windows_get_list();
for (; it; it = g_list_next(it)) {
PidginConvWindow *win = it->data;
scrncap_convwin_uninit(win);
PURPLE_PLUGIN_INIT(screencap, plugin_query, plugin_load, plugin_unload);