4 * Pidgin is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
25 #include "buddylist.h"
28 #include "whiteboard.h"
30 #include "gtk3compat.h"
31 #include "gtkwhiteboard.h"
35 PIDGIN_WHITEBOARD_BRUSH_UP
,
36 PIDGIN_WHITEBOARD_BRUSH_DOWN
,
37 PIDGIN_WHITEBOARD_BRUSH_MOTION
38 } PidginWhiteboardBrushState
;
40 typedef struct _PidginWhiteboard PidginWhiteboard
;
41 typedef struct _PidginWhiteboardPrivate PidginWhiteboardPrivate
;
43 struct _PidginWhiteboardPrivate
{
45 cairo_surface_t
*surface
;
50 * @priv: Internal data
51 * @wb: Backend data for this whiteboard
52 * @window: Window for the Doodle session
53 * @drawing_area: Drawing area
54 * @width: Canvas width
55 * @height: Canvas height
56 * @brush_color: Foreground color
57 * @brush_size: Brush size
61 struct _PidginWhiteboard
63 PidginWhiteboardPrivate
*priv
;
68 GtkWidget
*drawing_area
;
76 /******************************************************************************
78 *****************************************************************************/
79 static void pidgin_whiteboard_create(PurpleWhiteboard
*wb
);
81 static void pidgin_whiteboard_destroy(PurpleWhiteboard
*wb
);
82 static gboolean
whiteboard_close_cb(GtkWidget
*widget
, GdkEvent
*event
, PidginWhiteboard
*gtkwb
);
84 /*static void pidginwhiteboard_button_start_press(GtkButton *button, gpointer data); */
86 static gboolean
pidgin_whiteboard_configure_event(GtkWidget
*widget
, GdkEventConfigure
*event
, gpointer data
);
88 pidgin_whiteboard_draw_event(GtkWidget
*widget
, cairo_t
*cr
,
91 static gboolean
pidgin_whiteboard_brush_down(GtkWidget
*widget
, GdkEventButton
*event
, gpointer data
);
92 static gboolean
pidgin_whiteboard_brush_motion(GtkWidget
*widget
, GdkEventMotion
*event
, gpointer data
);
93 static gboolean
pidgin_whiteboard_brush_up(GtkWidget
*widget
, GdkEventButton
*event
, gpointer data
);
95 static void pidgin_whiteboard_draw_brush_point(PurpleWhiteboard
*wb
,
96 int x
, int y
, int color
, int size
);
97 static void pidgin_whiteboard_draw_brush_line(PurpleWhiteboard
*wb
, int x0
, int y0
,
98 int x1
, int y1
, int color
, int size
);
100 static void pidgin_whiteboard_set_dimensions(PurpleWhiteboard
*wb
, int width
, int height
);
101 static void pidgin_whiteboard_set_brush(PurpleWhiteboard
*wb
, int size
, int color
);
102 static void pidgin_whiteboard_clear(PurpleWhiteboard
*wb
);
104 static void pidgin_whiteboard_button_clear_press(GtkWidget
*widget
, gpointer data
);
105 static void pidgin_whiteboard_button_save_press(GtkWidget
*widget
, gpointer data
);
107 static void pidgin_whiteboard_set_canvas_as_icon(PidginWhiteboard
*gtkwb
);
109 static void pidgin_whiteboard_rgb24_to_rgba(int color_rgb
, GdkRGBA
*color
);
111 static void color_selected(GtkColorButton
*button
, PidginWhiteboard
*gtkwb
);
113 /******************************************************************************
115 *****************************************************************************/
117 static int LastX
; /* Tracks last position of the mouse when drawing */
119 static int MotionCount
; /* Tracks how many brush motions made */
120 static PidginWhiteboardBrushState brush_state
= PIDGIN_WHITEBOARD_BRUSH_UP
;
122 static PurpleWhiteboardUiOps ui_ops
=
124 pidgin_whiteboard_create
,
125 pidgin_whiteboard_destroy
,
126 pidgin_whiteboard_set_dimensions
,
127 pidgin_whiteboard_set_brush
,
128 pidgin_whiteboard_draw_brush_point
,
129 pidgin_whiteboard_draw_brush_line
,
130 pidgin_whiteboard_clear
,
137 /******************************************************************************
139 *****************************************************************************/
140 PurpleWhiteboardUiOps
*pidgin_whiteboard_get_ui_ops(void)
145 static void pidgin_whiteboard_create(PurpleWhiteboard
*wb
)
149 GtkWidget
*drawing_area
;
150 GtkWidget
*vbox_controls
;
151 GtkWidget
*hbox_canvas_and_controls
;
154 --------------------------
155 |[][][][palette[][][][][]|
156 |------------------------|
162 --------------------------
164 GtkWidget
*clear_button
;
165 GtkWidget
*save_button
;
166 GtkWidget
*color_button
;
169 PidginWhiteboard
*gtkwb
= g_new0(PidginWhiteboard
, 1);
170 gtkwb
->priv
= g_new0(PidginWhiteboardPrivate
, 1);
173 purple_whiteboard_set_ui_data(wb
, gtkwb
);
175 /* Get dimensions (default?) for the whiteboard canvas */
176 if (!purple_whiteboard_get_dimensions(wb
, >kwb
->width
, >kwb
->height
))
178 /* Give some initial board-size */
183 if (!purple_whiteboard_get_brush(wb
, >kwb
->brush_size
, >kwb
->brush_color
))
185 /* Give some initial brush-info */
186 gtkwb
->brush_size
= 2;
187 gtkwb
->brush_color
= 0xff0000;
190 /* Try and set window title as the name of the buddy, else just use their
193 buddy
= purple_blist_find_buddy(purple_whiteboard_get_account(wb
), purple_whiteboard_get_who(wb
));
195 window
= pidgin_create_window(buddy
!= NULL
? purple_buddy_get_contact_alias(buddy
) : purple_whiteboard_get_who(wb
), 0, NULL
, FALSE
);
196 gtkwb
->window
= window
;
197 gtk_widget_set_name(window
, purple_whiteboard_get_who(wb
));
199 g_signal_connect(G_OBJECT(window
), "delete_event",
200 G_CALLBACK(whiteboard_close_cb
), gtkwb
);
202 hbox_canvas_and_controls
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 0);
203 gtk_widget_show(hbox_canvas_and_controls
);
205 gtk_container_add(GTK_CONTAINER(window
), hbox_canvas_and_controls
);
206 gtk_container_set_border_width(GTK_CONTAINER(window
), PIDGIN_HIG_BORDER
);
208 /* Create the drawing area */
209 drawing_area
= gtk_drawing_area_new();
210 gtkwb
->drawing_area
= drawing_area
;
211 gtk_widget_set_size_request(GTK_WIDGET(drawing_area
), gtkwb
->width
, gtkwb
->height
);
212 gtk_box_pack_start(GTK_BOX(hbox_canvas_and_controls
), drawing_area
, TRUE
, TRUE
, PIDGIN_HIG_BOX_SPACE
);
214 gtk_widget_show(drawing_area
);
216 /* Signals used to handle backing pixmap */
217 g_signal_connect(G_OBJECT(drawing_area
), "draw",
218 G_CALLBACK(pidgin_whiteboard_draw_event
), gtkwb
);
220 g_signal_connect(G_OBJECT(drawing_area
), "configure-event",
221 G_CALLBACK(pidgin_whiteboard_configure_event
), gtkwb
);
224 g_signal_connect(G_OBJECT(drawing_area
), "button_press_event",
225 G_CALLBACK(pidgin_whiteboard_brush_down
), gtkwb
);
227 g_signal_connect(G_OBJECT(drawing_area
), "motion_notify_event",
228 G_CALLBACK(pidgin_whiteboard_brush_motion
), gtkwb
);
230 g_signal_connect(G_OBJECT(drawing_area
), "button_release_event",
231 G_CALLBACK(pidgin_whiteboard_brush_up
), gtkwb
);
233 gtk_widget_set_events(drawing_area
,
235 GDK_LEAVE_NOTIFY_MASK
|
236 GDK_BUTTON_PRESS_MASK
|
237 GDK_POINTER_MOTION_MASK
|
238 GDK_BUTTON_RELEASE_MASK
|
239 GDK_POINTER_MOTION_HINT_MASK
);
241 /* Create vertical box to contain the controls */
242 vbox_controls
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 0);
243 gtk_box_pack_start(GTK_BOX(hbox_canvas_and_controls
),
244 vbox_controls
, FALSE
, FALSE
, PIDGIN_HIG_BOX_SPACE
);
245 gtk_widget_show(vbox_controls
);
247 /* Add a clear button */
248 clear_button
= gtk_button_new_from_stock(GTK_STOCK_CLEAR
);
249 gtk_box_pack_start(GTK_BOX(vbox_controls
), clear_button
, FALSE
, FALSE
, PIDGIN_HIG_BOX_SPACE
);
250 gtk_widget_show(clear_button
);
251 g_signal_connect(G_OBJECT(clear_button
), "clicked",
252 G_CALLBACK(pidgin_whiteboard_button_clear_press
), gtkwb
);
254 /* Add a save button */
255 save_button
= gtk_button_new_from_stock(GTK_STOCK_SAVE
);
256 gtk_box_pack_start(GTK_BOX(vbox_controls
), save_button
, FALSE
, FALSE
, PIDGIN_HIG_BOX_SPACE
);
257 gtk_widget_show(save_button
);
259 g_signal_connect(G_OBJECT(save_button
), "clicked",
260 G_CALLBACK(pidgin_whiteboard_button_save_press
), gtkwb
);
262 /* Add a color selector */
263 color_button
= gtk_color_button_new();
264 gtk_box_pack_start(GTK_BOX(vbox_controls
), color_button
, FALSE
, FALSE
, PIDGIN_HIG_BOX_SPACE
);
265 gtk_widget_show(color_button
);
267 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(color_button
), FALSE
);
268 pidgin_whiteboard_rgb24_to_rgba(gtkwb
->brush_color
, &color
);
269 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(color_button
), &color
);
271 g_signal_connect(G_OBJECT(color_button
), "color-set",
272 G_CALLBACK(color_selected
), gtkwb
);
274 /* Make all this (window) visible */
275 gtk_widget_show(window
);
277 pidgin_whiteboard_set_canvas_as_icon(gtkwb
);
279 /* TODO Specific protocol/whiteboard assignment here? Needs a UI Op? */
280 /* Set default brush size and color */
282 ds->brush_size = DOODLE_BRUSH_MEDIUM;
287 static void pidgin_whiteboard_destroy(PurpleWhiteboard
*wb
)
289 PidginWhiteboard
*gtkwb
;
290 GtkWidget
*colour_dialog
;
292 g_return_if_fail(wb
!= NULL
);
293 gtkwb
= purple_whiteboard_get_ui_data(wb
);
294 g_return_if_fail(gtkwb
!= NULL
);
296 /* TODO Ask if user wants to save picture before the session is closed */
298 /* Clear graphical memory */
299 if (gtkwb
->priv
->cr
) {
300 cairo_destroy(gtkwb
->priv
->cr
);
301 gtkwb
->priv
->cr
= NULL
;
303 if (gtkwb
->priv
->surface
) {
304 cairo_surface_destroy(gtkwb
->priv
->surface
);
305 gtkwb
->priv
->surface
= NULL
;
308 colour_dialog
= g_object_get_data(G_OBJECT(gtkwb
->window
), "colour-dialog");
310 gtk_widget_destroy(colour_dialog
);
311 g_object_set_data(G_OBJECT(gtkwb
->window
), "colour-dialog", NULL
);
316 gtk_widget_destroy(gtkwb
->window
);
317 gtkwb
->window
= NULL
;
322 purple_whiteboard_set_ui_data(wb
, NULL
);
325 static gboolean
whiteboard_close_cb(GtkWidget
*widget
, GdkEvent
*event
, PidginWhiteboard
*gtkwb
)
327 PurpleWhiteboard
*wb
;
329 g_return_val_if_fail(gtkwb
!= NULL
, FALSE
);
331 g_return_val_if_fail(wb
!= NULL
, FALSE
);
339 * Whiteboard start button on conversation window (move this code to gtkconv?
340 * and use new protocol member?)
343 static void pidginwhiteboard_button_start_press(GtkButton
*button
, gpointer data
)
345 PurpleConversation
*conv
= data
;
346 PurpleAccount
*account
= purple_conversation_get_account(conv
);
347 PurpleConnection
*gc
= purple_account_get_connection(account
);
348 char *to
= (char*)(purple_conversation_get_name(conv
));
350 /* Only handle this if local client requested Doodle session (else local
351 * client would have sent one)
353 PurpleWhiteboard
*wb
= purple_whiteboard_get(account
, to
);
355 /* Write a local message to this conversation showing that a request for a
356 * Doodle session has been made
358 /* XXXX because otherwise gettext will see this string, even though it's
359 * in an #if 0 block. Remove the XXXX if you want to use this code.
360 * But, it really shouldn't be a Yahoo-specific string. ;) */
361 purple_im_conversation_write_message(PURPLE_CONV_IM(conv
), "", XXXX_("Sent Doodle request."),
362 PURPLE_MESSAGE_NICK
| PURPLE_MESSAGE_RECV
, time(NULL
));
364 yahoo_doodle_command_send_request(gc
, to
);
365 yahoo_doodle_command_send_ready(gc
, to
);
367 /* Insert this 'session' in the list. At this point, it's only a requested
370 wb
= purple_whiteboard_new(account
, to
, DOODLE_STATE_REQUESTING
);
374 static gboolean
pidgin_whiteboard_configure_event(GtkWidget
*widget
, GdkEventConfigure
*event
, gpointer data
)
376 PidginWhiteboard
*gtkwb
= (PidginWhiteboard
*)data
;
378 GtkAllocation allocation
;
379 GdkRGBA white
= {1.0, 1.0, 1.0, 1.0};
382 cairo_destroy(gtkwb
->priv
->cr
);
383 if (gtkwb
->priv
->surface
)
384 cairo_surface_destroy(gtkwb
->priv
->surface
);
386 gtk_widget_get_allocation(widget
, &allocation
);
388 gtkwb
->priv
->surface
= cairo_image_surface_create(CAIRO_FORMAT_RGB24
,
389 allocation
.width
, allocation
.height
);
390 gtkwb
->priv
->cr
= cr
= cairo_create(gtkwb
->priv
->surface
);
391 gdk_cairo_set_source_rgba(cr
, &white
);
392 cairo_rectangle(cr
, 0, 0, allocation
.width
, allocation
.height
);
399 pidgin_whiteboard_draw_event(GtkWidget
*widget
, cairo_t
*cr
,
402 PidginWhiteboard
*gtkwb
= _gtkwb
;
404 cairo_set_source_surface(cr
, gtkwb
->priv
->surface
, 0, 0);
410 static gboolean
pidgin_whiteboard_brush_down(GtkWidget
*widget
, GdkEventButton
*event
, gpointer data
)
412 PidginWhiteboard
*gtkwb
= (PidginWhiteboard
*)data
;
414 PurpleWhiteboard
*wb
= gtkwb
->wb
;
415 GList
*draw_list
= purple_whiteboard_get_draw_list(wb
);
417 if (brush_state
!= PIDGIN_WHITEBOARD_BRUSH_UP
) {
418 /* Potential double-click DOWN to DOWN? */
419 brush_state
= PIDGIN_WHITEBOARD_BRUSH_DOWN
;
424 brush_state
= PIDGIN_WHITEBOARD_BRUSH_DOWN
;
426 if(event
->button
== 1 && gtkwb
->priv
->cr
!= NULL
)
428 /* Check if draw_list has contents; if so, clear it */
431 purple_whiteboard_draw_list_destroy(draw_list
);
435 /* Set tracking variables */
441 draw_list
= g_list_append(draw_list
, GINT_TO_POINTER(LastX
));
442 draw_list
= g_list_append(draw_list
, GINT_TO_POINTER(LastY
));
444 pidgin_whiteboard_draw_brush_point(gtkwb
->wb
,
446 gtkwb
->brush_color
, gtkwb
->brush_size
);
449 purple_whiteboard_set_draw_list(wb
, draw_list
);
454 static gboolean
pidgin_whiteboard_brush_motion(GtkWidget
*widget
, GdkEventMotion
*event
, gpointer data
)
461 GdkModifierType state
;
463 PidginWhiteboard
*gtkwb
= (PidginWhiteboard
*)data
;
465 PurpleWhiteboard
*wb
= gtkwb
->wb
;
466 GList
*draw_list
= purple_whiteboard_get_draw_list(wb
);
469 gdk_window_get_device_position(event
->window
, event
->device
, &x
, &y
,
475 state
= event
->state
;
478 if(state
& GDK_BUTTON1_MASK
&& gtkwb
->priv
->cr
!= NULL
)
480 if ((brush_state
!= PIDGIN_WHITEBOARD_BRUSH_DOWN
) &&
481 (brush_state
!= PIDGIN_WHITEBOARD_BRUSH_MOTION
))
483 purple_debug_error("gtkwhiteboard",
484 "***Bad brush state transition %d to MOTION\n",
487 brush_state
= PIDGIN_WHITEBOARD_BRUSH_MOTION
;
491 brush_state
= PIDGIN_WHITEBOARD_BRUSH_MOTION
;
498 /* NOTE 100 is a temporary constant for how many deltas/motions in a
499 * stroke (needs UI Ops?)
501 if(MotionCount
== 100)
503 draw_list
= g_list_append(draw_list
, GINT_TO_POINTER(dx
));
504 draw_list
= g_list_append(draw_list
, GINT_TO_POINTER(dy
));
506 /* Send draw list to the draw_list handler */
507 purple_whiteboard_send_draw_list(gtkwb
->wb
, draw_list
);
509 /* The brush stroke is finished, clear the list for another one */
512 purple_whiteboard_draw_list_destroy(draw_list
);
516 /* Reset motion tracking */
519 draw_list
= g_list_append(draw_list
, GINT_TO_POINTER(LastX
));
520 draw_list
= g_list_append(draw_list
, GINT_TO_POINTER(LastY
));
526 draw_list
= g_list_append(draw_list
, GINT_TO_POINTER(dx
));
527 draw_list
= g_list_append(draw_list
, GINT_TO_POINTER(dy
));
529 pidgin_whiteboard_draw_brush_line(gtkwb
->wb
,
532 gtkwb
->brush_color
, gtkwb
->brush_size
);
534 /* Set tracking variables */
539 purple_whiteboard_set_draw_list(wb
, draw_list
);
544 static gboolean
pidgin_whiteboard_brush_up(GtkWidget
*widget
, GdkEventButton
*event
, gpointer data
)
546 PidginWhiteboard
*gtkwb
= (PidginWhiteboard
*)data
;
548 PurpleWhiteboard
*wb
= gtkwb
->wb
;
549 GList
*draw_list
= purple_whiteboard_get_draw_list(wb
);
551 if ((brush_state
!= PIDGIN_WHITEBOARD_BRUSH_DOWN
) &&
552 (brush_state
!= PIDGIN_WHITEBOARD_BRUSH_MOTION
))
554 purple_debug_error("gtkwhiteboard",
555 "***Bad brush state transition %d to UP\n",
558 brush_state
= PIDGIN_WHITEBOARD_BRUSH_UP
;
562 brush_state
= PIDGIN_WHITEBOARD_BRUSH_UP
;
564 if(event
->button
== 1 && gtkwb
->priv
->cr
!= NULL
)
566 /* If the brush was never moved, express two sets of two deltas That's a
567 * 'point,' but not for Yahoo!
569 /* if((event->x == LastX) && (event->y == LastY)) */
574 /* For Yahoo!, a (0 0) indicates the end of drawing */
575 /* FIXME: Yahoo Doodle specific! */
576 for(index
= 0; index
< 2; index
++)
578 draw_list
= g_list_append(draw_list
, 0);
579 draw_list
= g_list_append(draw_list
, 0);
587 /* Send draw list to protocol draw_list handler */
588 purple_whiteboard_send_draw_list(gtkwb
->wb
, draw_list
);
590 pidgin_whiteboard_set_canvas_as_icon(gtkwb
);
592 /* The brush stroke is finished, clear the list for another one */
594 purple_whiteboard_draw_list_destroy(draw_list
);
596 purple_whiteboard_set_draw_list(wb
, NULL
);
602 static void pidgin_whiteboard_draw_brush_point(PurpleWhiteboard
*wb
, int x
, int y
, int color
, int size
)
604 PidginWhiteboard
*gtkwb
= purple_whiteboard_get_ui_data(wb
);
605 GtkWidget
*widget
= gtkwb
->drawing_area
;
606 cairo_t
*gfx_con
= gtkwb
->priv
->cr
;
609 /* Interpret and convert color */
610 pidgin_whiteboard_rgb24_to_rgba(color
, &rgba
);
611 gdk_cairo_set_source_rgba(gfx_con
, &rgba
);
620 gtk_widget_queue_draw_area(widget
,
621 x
- size
/ 2, y
- size
/ 2,
625 /* Uses Bresenham's algorithm (as provided by Wikipedia) */
626 static void pidgin_whiteboard_draw_brush_line(PurpleWhiteboard
*wb
, int x0
, int y0
, int x1
, int y1
, int color
, int size
)
642 gboolean steep
= abs(y1
- y0
) > abs(x1
- x0
);
646 temp
= x0
; x0
= y0
; y0
= temp
;
647 temp
= x1
; x1
= y1
; y1
= temp
;
670 pidgin_whiteboard_draw_brush_point(wb
, y
, x
, color
, size
);
672 pidgin_whiteboard_draw_brush_point(wb
, x
, y
, color
, size
);
679 if((error
* 2) >= dx
)
686 pidgin_whiteboard_draw_brush_point(wb
, y
, x
, color
, size
);
688 pidgin_whiteboard_draw_brush_point(wb
, x
, y
, color
, size
);
692 static void pidgin_whiteboard_set_dimensions(PurpleWhiteboard
*wb
, int width
, int height
)
694 PidginWhiteboard
*gtkwb
= purple_whiteboard_get_ui_data(wb
);
696 gtkwb
->width
= width
;
697 gtkwb
->height
= height
;
700 static void pidgin_whiteboard_set_brush(PurpleWhiteboard
*wb
, int size
, int color
)
702 PidginWhiteboard
*gtkwb
= purple_whiteboard_get_ui_data(wb
);
704 gtkwb
->brush_size
= size
;
705 gtkwb
->brush_color
= color
;
708 static void pidgin_whiteboard_clear(PurpleWhiteboard
*wb
)
710 PidginWhiteboard
*gtkwb
= purple_whiteboard_get_ui_data(wb
);
711 GtkWidget
*drawing_area
= gtkwb
->drawing_area
;
712 cairo_t
*cr
= gtkwb
->priv
->cr
;
713 GtkAllocation allocation
;
714 GdkRGBA white
= {1.0, 1.0, 1.0, 1.0};
716 gtk_widget_get_allocation(drawing_area
, &allocation
);
718 gdk_cairo_set_source_rgba(cr
, &white
);
719 cairo_rectangle(cr
, 0, 0, allocation
.width
, allocation
.height
);
722 gtk_widget_queue_draw_area(drawing_area
, 0, 0,
723 allocation
.width
, allocation
.height
);
726 static void pidgin_whiteboard_button_clear_press(GtkWidget
*widget
, gpointer data
)
728 PidginWhiteboard
*gtkwb
= (PidginWhiteboard
*)(data
);
730 /* Confirm whether the user really wants to clear */
731 GtkWidget
*dialog
= gtk_message_dialog_new(GTK_WINDOW(gtkwb
->window
),
732 GTK_DIALOG_DESTROY_WITH_PARENT
,
733 GTK_MESSAGE_QUESTION
,
735 _("Do you really want to clear?"));
736 gint response
= gtk_dialog_run(GTK_DIALOG(dialog
));
737 gtk_widget_destroy(dialog
);
739 if (response
== GTK_RESPONSE_YES
)
741 pidgin_whiteboard_clear(gtkwb
->wb
);
743 pidgin_whiteboard_set_canvas_as_icon(gtkwb
);
745 /* Do protocol specific clearing procedures */
746 purple_whiteboard_send_clear(gtkwb
->wb
);
751 pidgin_whiteboard_button_save_press(GtkWidget
*widget
, gpointer _gtkwb
)
753 PidginWhiteboard
*gtkwb
= _gtkwb
;
758 dialog
= gtk_file_chooser_dialog_new(_("Save File"),
759 GTK_WINDOW(gtkwb
->window
), GTK_FILE_CHOOSER_ACTION_SAVE
,
760 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
, GTK_STOCK_SAVE
,
761 GTK_RESPONSE_ACCEPT
, NULL
);
763 gtk_file_chooser_set_do_overwrite_confirmation(
764 GTK_FILE_CHOOSER(dialog
), TRUE
);
766 gtk_file_chooser_set_current_name(
767 GTK_FILE_CHOOSER(dialog
), "whiteboard.png");
769 result
= gtk_dialog_run(GTK_DIALOG(dialog
));
771 if (result
== GTK_RESPONSE_ACCEPT
) {
774 gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog
));
776 gtk_widget_destroy(dialog
);
778 pixbuf
= gdk_pixbuf_get_from_surface(gtkwb
->priv
->surface
, 0, 0,
779 gtkwb
->width
, gtkwb
->height
);
781 success
= gdk_pixbuf_save(pixbuf
, filename
, "png", NULL
,
782 "compression", "9", NULL
);
783 g_object_unref(pixbuf
);
785 purple_debug_info("gtkwhiteboard",
786 "whiteboard saved to \"%s\"", filename
);
788 purple_notify_error(NULL
, _("Whiteboard"),
789 _("Unable to save the file"), NULL
, NULL
);
790 purple_debug_error("gtkwhiteboard", "whiteboard "
791 "couldn't be saved to \"%s\"", filename
);
794 } else if (result
== GTK_RESPONSE_CANCEL
)
795 gtk_widget_destroy(dialog
);
798 static void pidgin_whiteboard_set_canvas_as_icon(PidginWhiteboard
*gtkwb
)
802 /* Makes an icon from the whiteboard's canvas 'image' */
803 pixbuf
= gdk_pixbuf_get_from_surface(gtkwb
->priv
->surface
,
804 0, 0, gtkwb
->width
, gtkwb
->height
);
805 gtk_window_set_icon(GTK_WINDOW(gtkwb
->window
), pixbuf
);
806 g_object_unref(pixbuf
);
809 static void pidgin_whiteboard_rgb24_to_rgba(int color_rgb
, GdkRGBA
*color
)
811 color
->red
= ((color_rgb
>> 16) & 0xFF) / 255.0f
;
812 color
->green
= ((color_rgb
>> 8) & 0xFF) / 255.0f
;
813 color
->blue
= (color_rgb
& 0xFF) / 255.0f
;
817 color_selected(GtkColorButton
*button
, PidginWhiteboard
*gtkwb
)
820 PurpleWhiteboard
*wb
= gtkwb
->wb
;
821 int old_size
, old_color
;
824 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(button
), &color
);
826 new_color
= (unsigned int)(color
.red
* 255) << 16;
827 new_color
|= (unsigned int)(color
.green
* 255) << 8;
828 new_color
|= (unsigned int)(color
.blue
* 255);
830 purple_whiteboard_get_brush(wb
, &old_size
, &old_color
);
831 purple_whiteboard_send_brush(wb
, old_size
, new_color
);