Move the sound theme selector to the Themes tab and make the smiley section
[pidgin-git.git] / pidgin / gtkwhiteboard.c
blob80564c88e5e077abf64a3e8325258204ac3f6b4d
1 /*
2 * pidgin
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
6 * source distribution.
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
24 #include <stdlib.h>
26 #include "internal.h"
27 #include "blist.h"
28 #include "debug.h"
30 #include "gtkwhiteboard.h"
31 #include "gtkutils.h"
33 /******************************************************************************
34 * Prototypes
35 *****************************************************************************/
36 static void pidgin_whiteboard_create(PurpleWhiteboard *wb);
38 static void pidgin_whiteboard_destroy(PurpleWhiteboard *wb);
39 static gboolean whiteboard_close_cb(GtkWidget *widget, GdkEvent *event, PidginWhiteboard *gtkwb);
41 /*static void pidginwhiteboard_button_start_press(GtkButton *button, gpointer data); */
43 static gboolean pidgin_whiteboard_configure_event(GtkWidget *widget, GdkEventConfigure *event, gpointer data);
44 static gboolean pidgin_whiteboard_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data);
46 static gboolean pidgin_whiteboard_brush_down(GtkWidget *widget, GdkEventButton *event, gpointer data);
47 static gboolean pidgin_whiteboard_brush_motion(GtkWidget *widget, GdkEventMotion *event, gpointer data);
48 static gboolean pidgin_whiteboard_brush_up(GtkWidget *widget, GdkEventButton *event, gpointer data);
50 static void pidgin_whiteboard_draw_brush_point(PurpleWhiteboard *wb,
51 int x, int y, int color, int size);
52 static void pidgin_whiteboard_draw_brush_line(PurpleWhiteboard *wb, int x0, int y0,
53 int x1, int y1, int color, int size);
55 static void pidgin_whiteboard_set_dimensions(PurpleWhiteboard *wb, int width, int height);
56 static void pidgin_whiteboard_set_brush(PurpleWhiteboard *wb, int size, int color);
57 static void pidgin_whiteboard_clear(PurpleWhiteboard *wb);
59 static void pidgin_whiteboard_button_clear_press(GtkWidget *widget, gpointer data);
60 static void pidgin_whiteboard_button_save_press(GtkWidget *widget, gpointer data);
62 static void pidgin_whiteboard_set_canvas_as_icon(PidginWhiteboard *gtkwb);
64 static void pidgin_whiteboard_rgb24_to_rgb48(int color_rgb, GdkColor *color);
66 static void color_select_dialog(GtkWidget *widget, PidginWhiteboard *gtkwb);
68 /******************************************************************************
69 * Globals
70 *****************************************************************************/
72 GList *buttonList = NULL;
73 GdkColor DefaultColor[PALETTE_NUM_COLORS];
76 static int LastX; /* Tracks last position of the mouse when drawing */
77 static int LastY;
78 static int MotionCount; /* Tracks how many brush motions made */
79 static int BrushState = BRUSH_STATE_UP;
81 static PurpleWhiteboardUiOps ui_ops =
83 pidgin_whiteboard_create,
84 pidgin_whiteboard_destroy,
85 pidgin_whiteboard_set_dimensions,
86 pidgin_whiteboard_set_brush,
87 pidgin_whiteboard_draw_brush_point,
88 pidgin_whiteboard_draw_brush_line,
89 pidgin_whiteboard_clear,
90 NULL,
91 NULL,
92 NULL,
93 NULL
96 /******************************************************************************
97 * API
98 *****************************************************************************/
99 PurpleWhiteboardUiOps *pidgin_whiteboard_get_ui_ops(void)
101 return &ui_ops;
104 static void pidgin_whiteboard_create(PurpleWhiteboard *wb)
106 PurpleBuddy *buddy;
107 GtkWidget *window;
108 GtkWidget *drawing_area;
109 GtkWidget *vbox_controls;
110 GtkWidget *hbox_canvas_and_controls;
113 --------------------------
114 |[][][][palette[][][][][]|
115 |------------------------|
116 | canvas | con |
117 | | trol|
118 | | s |
119 | | |
120 | | |
121 --------------------------
123 GtkWidget *clear_button;
124 GtkWidget *save_button;
125 GtkWidget *color_button;
127 PidginWhiteboard *gtkwb = g_new0(PidginWhiteboard, 1);
129 gtkwb->wb = wb;
130 wb->ui_data = gtkwb;
132 /* Get dimensions (default?) for the whiteboard canvas */
133 if (!purple_whiteboard_get_dimensions(wb, &gtkwb->width, &gtkwb->height))
135 /* Give some initial board-size */
136 gtkwb->width = 300;
137 gtkwb->height = 250;
140 if (!purple_whiteboard_get_brush(wb, &gtkwb->brush_size, &gtkwb->brush_color))
142 /* Give some initial brush-info */
143 gtkwb->brush_size = 2;
144 gtkwb->brush_color = 0xff0000;
147 /* Try and set window title as the name of the buddy, else just use their
148 * username
150 buddy = purple_find_buddy(wb->account, wb->who);
152 window = pidgin_create_window(buddy != NULL ? purple_buddy_get_contact_alias(buddy) : wb->who, 0, NULL, FALSE);
153 gtkwb->window = window;
154 gtk_widget_set_name(window, wb->who);
156 g_signal_connect(G_OBJECT(window), "delete_event",
157 G_CALLBACK(whiteboard_close_cb), gtkwb);
159 #if 0
160 int i;
162 GtkWidget *hbox_palette;
163 GtkWidget *vbox_palette_above_canvas_and_controls;
164 GtkWidget *palette_color_box[PALETTE_NUM_COLORS];
166 /* Create vertical box to place palette above the canvas and controls */
167 vbox_palette_above_canvas_and_controls = gtk_vbox_new(FALSE, 0);
168 gtk_container_add(GTK_CONTAINER(window), vbox_palette_above_canvas_and_controls);
169 gtk_widget_show(vbox_palette_above_canvas_and_controls);
171 /* Create horizontal box for the palette and all its entries */
172 hbox_palette = gtk_hbox_new(FALSE, 0);
173 gtk_box_pack_start(GTK_BOX(vbox_palette_above_canvas_and_controls),
174 hbox_palette, FALSE, FALSE, PIDGIN_HIG_BORDER);
175 gtk_widget_show(hbox_palette);
177 /* Create horizontal box to seperate the canvas from the controls */
178 hbox_canvas_and_controls = gtk_hbox_new(FALSE, 0);
179 gtk_box_pack_start(GTK_BOX(vbox_palette_above_canvas_and_controls),
180 hbox_canvas_and_controls, FALSE, FALSE, PIDGIN_HIG_BORDER);
181 gtk_widget_show(hbox_canvas_and_controls);
183 for(i = 0; i < PALETTE_NUM_COLORS; i++)
185 palette_color_box[i] = gtk_image_new_from_pixbuf(NULL);
186 gtk_widget_set_size_request(palette_color_box[i], gtkwb->width / PALETTE_NUM_COLORS ,32);
187 gtk_container_add(GTK_CONTAINER(hbox_palette), palette_color_box[i]);
189 gtk_widget_show(palette_color_box[i]);
191 #endif
193 hbox_canvas_and_controls = gtk_hbox_new(FALSE, 0);
194 gtk_widget_show(hbox_canvas_and_controls);
196 gtk_container_add(GTK_CONTAINER(window), hbox_canvas_and_controls);
197 gtk_container_set_border_width(GTK_CONTAINER(window), PIDGIN_HIG_BORDER);
199 /* Create the drawing area */
200 drawing_area = gtk_drawing_area_new();
201 gtkwb->drawing_area = drawing_area;
202 gtk_widget_set_size_request(GTK_WIDGET(drawing_area), gtkwb->width, gtkwb->height);
203 gtk_box_pack_start(GTK_BOX(hbox_canvas_and_controls), drawing_area, TRUE, TRUE, PIDGIN_HIG_BOX_SPACE);
205 gtk_widget_show(drawing_area);
207 /* Signals used to handle backing pixmap */
208 g_signal_connect(G_OBJECT(drawing_area), "expose_event",
209 G_CALLBACK(pidgin_whiteboard_expose_event), gtkwb);
211 g_signal_connect(G_OBJECT(drawing_area), "configure_event",
212 G_CALLBACK(pidgin_whiteboard_configure_event), gtkwb);
214 /* Event signals */
215 g_signal_connect(G_OBJECT(drawing_area), "button_press_event",
216 G_CALLBACK(pidgin_whiteboard_brush_down), gtkwb);
218 g_signal_connect(G_OBJECT(drawing_area), "motion_notify_event",
219 G_CALLBACK(pidgin_whiteboard_brush_motion), gtkwb);
221 g_signal_connect(G_OBJECT(drawing_area), "button_release_event",
222 G_CALLBACK(pidgin_whiteboard_brush_up), gtkwb);
224 gtk_widget_set_events(drawing_area,
225 GDK_EXPOSURE_MASK |
226 GDK_LEAVE_NOTIFY_MASK |
227 GDK_BUTTON_PRESS_MASK |
228 GDK_POINTER_MOTION_MASK |
229 GDK_BUTTON_RELEASE_MASK |
230 GDK_POINTER_MOTION_HINT_MASK);
232 /* Create vertical box to contain the controls */
233 vbox_controls = gtk_vbox_new(FALSE, 0);
234 gtk_box_pack_start(GTK_BOX(hbox_canvas_and_controls),
235 vbox_controls, FALSE, FALSE, PIDGIN_HIG_BOX_SPACE);
236 gtk_widget_show(vbox_controls);
238 /* Add a clear button */
239 clear_button = gtk_button_new_from_stock(GTK_STOCK_CLEAR);
240 gtk_box_pack_start(GTK_BOX(vbox_controls), clear_button, FALSE, FALSE, PIDGIN_HIG_BOX_SPACE);
241 gtk_widget_show(clear_button);
242 g_signal_connect(G_OBJECT(clear_button), "clicked",
243 G_CALLBACK(pidgin_whiteboard_button_clear_press), gtkwb);
245 /* Add a save button */
246 save_button = gtk_button_new_from_stock(GTK_STOCK_SAVE);
247 gtk_box_pack_start(GTK_BOX(vbox_controls), save_button, FALSE, FALSE, PIDGIN_HIG_BOX_SPACE);
248 gtk_widget_show(save_button);
250 g_signal_connect(G_OBJECT(save_button), "clicked",
251 G_CALLBACK(pidgin_whiteboard_button_save_press), gtkwb);
253 /* Add a color selector */
254 color_button = gtk_button_new_from_stock(GTK_STOCK_SELECT_COLOR);
255 gtk_box_pack_start(GTK_BOX(vbox_controls), color_button, FALSE, FALSE, PIDGIN_HIG_BOX_SPACE);
256 gtk_widget_show(color_button);
257 g_signal_connect(G_OBJECT(color_button), "clicked",
258 G_CALLBACK(color_select_dialog), gtkwb);
260 /* Make all this (window) visible */
261 gtk_widget_show(window);
263 pidgin_whiteboard_set_canvas_as_icon(gtkwb);
265 /* TODO Specific protocol/whiteboard assignment here? Needs a UI Op? */
266 /* Set default brush size and color */
268 ds->brush_size = DOODLE_BRUSH_MEDIUM;
269 ds->brush_color = 0;
273 static void pidgin_whiteboard_destroy(PurpleWhiteboard *wb)
275 PidginWhiteboard *gtkwb;
276 GtkWidget *colour_dialog;
278 g_return_if_fail(wb != NULL);
279 gtkwb = wb->ui_data;
280 g_return_if_fail(gtkwb != NULL);
282 /* TODO Ask if user wants to save picture before the session is closed */
284 /* Clear graphical memory */
285 if(gtkwb->pixmap)
287 g_object_unref(gtkwb->pixmap);
288 gtkwb->pixmap = NULL;
291 colour_dialog = g_object_get_data(G_OBJECT(gtkwb->window), "colour-dialog");
292 if (colour_dialog) {
293 gtk_widget_destroy(colour_dialog);
294 g_object_set_data(G_OBJECT(gtkwb->window), "colour-dialog", NULL);
297 if(gtkwb->window)
299 gtk_widget_destroy(gtkwb->window);
300 gtkwb->window = NULL;
302 g_free(gtkwb);
303 wb->ui_data = NULL;
306 static gboolean whiteboard_close_cb(GtkWidget *widget, GdkEvent *event, PidginWhiteboard *gtkwb)
308 PurpleWhiteboard *wb;
310 g_return_val_if_fail(gtkwb != NULL, FALSE);
311 wb = gtkwb->wb;
312 g_return_val_if_fail(wb != NULL, FALSE);
314 purple_whiteboard_destroy(wb);
316 return FALSE;
320 * Whiteboard start button on conversation window (move this code to gtkconv?
321 * and use new prpl_info member?)
323 #if 0
324 static void pidginwhiteboard_button_start_press(GtkButton *button, gpointer data)
326 PurpleConversation *conv = data;
327 PurpleAccount *account = purple_conversation_get_account(conv);
328 PurpleConnection *gc = purple_account_get_connection(account);
329 char *to = (char*)(purple_conversation_get_name(conv));
331 /* Only handle this if local client requested Doodle session (else local
332 * client would have sent one)
334 PurpleWhiteboard *wb = purple_whiteboard_get(account, to);
336 /* Write a local message to this conversation showing that a request for a
337 * Doodle session has been made
339 /* XXXX because otherwise gettext will see this string, even though it's
340 * in an #if 0 block. Remove the XXXX if you want to use this code.
341 * But, it really shouldn't be a Yahoo-specific string. ;) */
342 purple_conv_im_write(PURPLE_CONV_IM(conv), "", XXXX_("Sent Doodle request."),
343 PURPLE_MESSAGE_NICK | PURPLE_MESSAGE_RECV, time(NULL));
345 yahoo_doodle_command_send_request(gc, to);
346 yahoo_doodle_command_send_ready(gc, to);
348 /* Insert this 'session' in the list. At this point, it's only a requested
349 * session.
351 wb = purple_whiteboard_create(account, to, DOODLE_STATE_REQUESTING);
353 #endif
355 static gboolean pidgin_whiteboard_configure_event(GtkWidget *widget, GdkEventConfigure *event, gpointer data)
357 PidginWhiteboard *gtkwb = (PidginWhiteboard*)data;
359 GdkPixmap *pixmap = gtkwb->pixmap;
361 if(pixmap)
362 g_object_unref(pixmap);
364 pixmap = gdk_pixmap_new(widget->window,
365 widget->allocation.width,
366 widget->allocation.height,
367 -1);
369 gtkwb->pixmap = pixmap;
371 gdk_draw_rectangle(pixmap,
372 widget->style->white_gc,
373 TRUE,
374 0, 0,
375 widget->allocation.width,
376 widget->allocation.height);
378 return TRUE;
381 static gboolean pidgin_whiteboard_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
383 PidginWhiteboard *gtkwb = (PidginWhiteboard*)(data);
384 GdkPixmap *pixmap = gtkwb->pixmap;
386 gdk_draw_drawable(widget->window,
387 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
388 pixmap,
389 event->area.x, event->area.y,
390 event->area.x, event->area.y,
391 event->area.width, event->area.height);
393 return FALSE;
396 static gboolean pidgin_whiteboard_brush_down(GtkWidget *widget, GdkEventButton *event, gpointer data)
398 PidginWhiteboard *gtkwb = (PidginWhiteboard*)data;
399 GdkPixmap *pixmap = gtkwb->pixmap;
401 PurpleWhiteboard *wb = gtkwb->wb;
402 GList *draw_list = wb->draw_list;
404 if(BrushState != BRUSH_STATE_UP)
406 /* Potential double-click DOWN to DOWN? */
407 BrushState = BRUSH_STATE_DOWN;
409 /* return FALSE; */
412 BrushState = BRUSH_STATE_DOWN;
414 if(event->button == 1 && pixmap != NULL)
416 /* Check if draw_list has contents; if so, clear it */
417 if(draw_list)
419 purple_whiteboard_draw_list_destroy(draw_list);
420 draw_list = NULL;
423 /* Set tracking variables */
424 LastX = event->x;
425 LastY = event->y;
427 MotionCount = 0;
429 draw_list = g_list_append(draw_list, GINT_TO_POINTER(LastX));
430 draw_list = g_list_append(draw_list, GINT_TO_POINTER(LastY));
432 pidgin_whiteboard_draw_brush_point(gtkwb->wb,
433 event->x, event->y,
434 gtkwb->brush_color, gtkwb->brush_size);
437 wb->draw_list = draw_list;
439 return TRUE;
442 static gboolean pidgin_whiteboard_brush_motion(GtkWidget *widget, GdkEventMotion *event, gpointer data)
444 int x;
445 int y;
446 int dx;
447 int dy;
449 GdkModifierType state;
451 PidginWhiteboard *gtkwb = (PidginWhiteboard*)data;
452 GdkPixmap *pixmap = gtkwb->pixmap;
454 PurpleWhiteboard *wb = gtkwb->wb;
455 GList *draw_list = wb->draw_list;
457 if(event->is_hint)
458 gdk_window_get_pointer(event->window, &x, &y, &state);
459 else
461 x = event->x;
462 y = event->y;
463 state = event->state;
466 if(state & GDK_BUTTON1_MASK && pixmap != NULL)
468 if((BrushState != BRUSH_STATE_DOWN) && (BrushState != BRUSH_STATE_MOTION))
470 purple_debug_error("gtkwhiteboard", "***Bad brush state transition %d to MOTION\n", BrushState);
472 BrushState = BRUSH_STATE_MOTION;
474 return FALSE;
476 BrushState = BRUSH_STATE_MOTION;
478 dx = x - LastX;
479 dy = y - LastY;
481 MotionCount++;
483 /* NOTE 100 is a temporary constant for how many deltas/motions in a
484 * stroke (needs UI Ops?)
486 if(MotionCount == 100)
488 draw_list = g_list_append(draw_list, GINT_TO_POINTER(dx));
489 draw_list = g_list_append(draw_list, GINT_TO_POINTER(dy));
491 /* Send draw list to the draw_list handler */
492 purple_whiteboard_send_draw_list(gtkwb->wb, draw_list);
494 /* The brush stroke is finished, clear the list for another one */
495 if(draw_list)
497 purple_whiteboard_draw_list_destroy(draw_list);
498 draw_list = NULL;
501 /* Reset motion tracking */
502 MotionCount = 0;
504 draw_list = g_list_append(draw_list, GINT_TO_POINTER(LastX));
505 draw_list = g_list_append(draw_list, GINT_TO_POINTER(LastY));
507 dx = x - LastX;
508 dy = y - LastY;
511 draw_list = g_list_append(draw_list, GINT_TO_POINTER(dx));
512 draw_list = g_list_append(draw_list, GINT_TO_POINTER(dy));
514 pidgin_whiteboard_draw_brush_line(gtkwb->wb,
515 LastX, LastY,
516 x, y,
517 gtkwb->brush_color, gtkwb->brush_size);
519 /* Set tracking variables */
520 LastX = x;
521 LastY = y;
524 wb->draw_list = draw_list;
526 return TRUE;
529 static gboolean pidgin_whiteboard_brush_up(GtkWidget *widget, GdkEventButton *event, gpointer data)
531 PidginWhiteboard *gtkwb = (PidginWhiteboard*)data;
532 GdkPixmap *pixmap = gtkwb->pixmap;
534 PurpleWhiteboard *wb = gtkwb->wb;
535 GList *draw_list = wb->draw_list;
537 if((BrushState != BRUSH_STATE_DOWN) && (BrushState != BRUSH_STATE_MOTION))
539 purple_debug_error("gtkwhiteboard", "***Bad brush state transition %d to UP\n", BrushState);
541 BrushState = BRUSH_STATE_UP;
543 return FALSE;
545 BrushState = BRUSH_STATE_UP;
547 if(event->button == 1 && pixmap != NULL)
549 /* If the brush was never moved, express two sets of two deltas That's a
550 * 'point,' but not for Yahoo!
552 /* if((event->x == LastX) && (event->y == LastY)) */
553 if(MotionCount == 0)
555 int index;
557 /* For Yahoo!, a (0 0) indicates the end of drawing */
558 /* FIXME: Yahoo Doodle specific! */
559 for(index = 0; index < 2; index++)
561 draw_list = g_list_append(draw_list, 0);
562 draw_list = g_list_append(draw_list, 0);
566 else
567 MotionCount = 0;
570 /* Send draw list to prpl draw_list handler */
571 purple_whiteboard_send_draw_list(gtkwb->wb, draw_list);
573 pidgin_whiteboard_set_canvas_as_icon(gtkwb);
575 /* The brush stroke is finished, clear the list for another one */
576 if(draw_list)
577 purple_whiteboard_draw_list_destroy(draw_list);
579 wb->draw_list = NULL;
582 return TRUE;
585 static void pidgin_whiteboard_draw_brush_point(PurpleWhiteboard *wb, int x, int y, int color, int size)
587 PidginWhiteboard *gtkwb = wb->ui_data;
588 GtkWidget *widget = gtkwb->drawing_area;
589 GdkPixmap *pixmap = gtkwb->pixmap;
591 GdkRectangle update_rect;
593 GdkGC *gfx_con = gdk_gc_new(pixmap);
594 GdkColor col;
596 update_rect.x = x - size / 2;
597 update_rect.y = y - size / 2;
598 update_rect.width = size;
599 update_rect.height = size;
601 /* Interpret and convert color */
602 pidgin_whiteboard_rgb24_to_rgb48(color, &col);
604 gdk_gc_set_rgb_fg_color(gfx_con, &col);
605 /* gdk_gc_set_rgb_bg_color(gfx_con, &col); */
607 /* NOTE 5 is a size constant for now... this is because of how poorly the
608 * gdk_draw_arc draws small circles
610 if(size < 5)
612 /* Draw a rectangle/square */
613 gdk_draw_rectangle(pixmap,
614 gfx_con,
615 TRUE,
616 update_rect.x, update_rect.y,
617 update_rect.width, update_rect.height);
619 else
621 /* Draw a circle */
622 gdk_draw_arc(pixmap,
623 gfx_con,
624 TRUE,
625 update_rect.x, update_rect.y,
626 update_rect.width, update_rect.height,
627 0, FULL_CIRCLE_DEGREES);
630 gtk_widget_queue_draw_area(widget,
631 update_rect.x, update_rect.y,
632 update_rect.width, update_rect.height);
634 g_object_unref(G_OBJECT(gfx_con));
637 /* Uses Bresenham's algorithm (as provided by Wikipedia) */
638 static void pidgin_whiteboard_draw_brush_line(PurpleWhiteboard *wb, int x0, int y0, int x1, int y1, int color, int size)
640 int temp;
642 int xstep;
643 int ystep;
645 int dx;
646 int dy;
648 int error;
649 int derror;
651 int x;
652 int y;
654 gboolean steep = abs(y1 - y0) > abs(x1 - x0);
656 if(steep)
658 temp = x0; x0 = y0; y0 = temp;
659 temp = x1; x1 = y1; y1 = temp;
662 dx = abs(x1 - x0);
663 dy = abs(y1 - y0);
665 error = 0;
666 derror = dy;
668 x = x0;
669 y = y0;
671 if(x0 < x1)
672 xstep = 1;
673 else
674 xstep = -1;
676 if(y0 < y1)
677 ystep = 1;
678 else
679 ystep = -1;
681 if(steep)
682 pidgin_whiteboard_draw_brush_point(wb, y, x, color, size);
683 else
684 pidgin_whiteboard_draw_brush_point(wb, x, y, color, size);
686 while(x != x1)
688 x += xstep;
689 error += derror;
691 if((error * 2) >= dx)
693 y += ystep;
694 error -= dx;
697 if(steep)
698 pidgin_whiteboard_draw_brush_point(wb, y, x, color, size);
699 else
700 pidgin_whiteboard_draw_brush_point(wb, x, y, color, size);
704 static void pidgin_whiteboard_set_dimensions(PurpleWhiteboard *wb, int width, int height)
706 PidginWhiteboard *gtkwb = wb->ui_data;
708 gtkwb->width = width;
709 gtkwb->height = height;
712 static void pidgin_whiteboard_set_brush(PurpleWhiteboard *wb, int size, int color)
714 PidginWhiteboard *gtkwb = wb->ui_data;
716 gtkwb->brush_size = size;
717 gtkwb->brush_color = color;
720 static void pidgin_whiteboard_clear(PurpleWhiteboard *wb)
722 PidginWhiteboard *gtkwb = wb->ui_data;
723 GdkPixmap *pixmap = gtkwb->pixmap;
724 GtkWidget *drawing_area = gtkwb->drawing_area;
726 gdk_draw_rectangle(pixmap,
727 drawing_area->style->white_gc,
728 TRUE,
729 0, 0,
730 drawing_area->allocation.width,
731 drawing_area->allocation.height);
733 gtk_widget_queue_draw_area(drawing_area,
734 0, 0,
735 drawing_area->allocation.width,
736 drawing_area->allocation.height);
739 static void pidgin_whiteboard_button_clear_press(GtkWidget *widget, gpointer data)
741 PidginWhiteboard *gtkwb = (PidginWhiteboard*)(data);
743 pidgin_whiteboard_clear(gtkwb->wb);
745 pidgin_whiteboard_set_canvas_as_icon(gtkwb);
747 /* Do protocol specific clearing procedures */
748 purple_whiteboard_send_clear(gtkwb->wb);
751 static void pidgin_whiteboard_button_save_press(GtkWidget *widget, gpointer data)
753 PidginWhiteboard *gtkwb = (PidginWhiteboard*)(data);
754 GdkPixbuf *pixbuf;
756 GtkWidget *dialog;
758 int result;
760 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
761 dialog = gtk_file_chooser_dialog_new (_("Save File"),
762 GTK_WINDOW(gtkwb->window),
763 GTK_FILE_CHOOSER_ACTION_SAVE,
764 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
765 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
766 NULL);
768 /* gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), (gboolean)(TRUE)); */
770 /* if(user_edited_a_new_document) */
772 /* gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), default_folder_for_saving); */
773 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "whiteboard.jpg");
776 else
777 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog), filename_for_existing_document);
779 #else
780 dialog = gtk_file_selection_new(_("Save File"));
781 gtk_file_selection_set_filename(GTK_FILE_SELECTION(dialog), "whiteboard.jpg");
782 #endif
783 result = gtk_dialog_run(GTK_DIALOG(dialog));
785 if(result == GTK_RESPONSE_ACCEPT)
787 char *filename;
789 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
790 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
791 #else
792 filename = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(dialog)));
793 #endif
794 gtk_widget_destroy(dialog);
796 /* Makes an icon from the whiteboard's canvas 'image' */
797 pixbuf = gdk_pixbuf_get_from_drawable(NULL,
798 (GdkDrawable*)(gtkwb->pixmap),
799 gdk_drawable_get_colormap(gtkwb->pixmap),
800 0, 0,
801 0, 0,
802 gtkwb->width, gtkwb->height);
804 if(gdk_pixbuf_save(pixbuf, filename, "jpeg", NULL, "quality", "100", NULL))
805 purple_debug_info("gtkwhiteboard", "File Saved...\n");
806 else
807 purple_debug_info("gtkwhiteboard", "File not Saved... Error\n");
808 g_free(filename);
810 else if(result == GTK_RESPONSE_CANCEL)
812 gtk_widget_destroy(dialog);
814 purple_debug_info("gtkwhiteboard", "File not Saved... Cancelled\n");
818 static void pidgin_whiteboard_set_canvas_as_icon(PidginWhiteboard *gtkwb)
820 GdkPixbuf *pixbuf;
822 /* Makes an icon from the whiteboard's canvas 'image' */
823 pixbuf = gdk_pixbuf_get_from_drawable(NULL,
824 (GdkDrawable*)(gtkwb->pixmap),
825 gdk_drawable_get_colormap(gtkwb->pixmap),
826 0, 0,
827 0, 0,
828 gtkwb->width, gtkwb->height);
830 gtk_window_set_icon((GtkWindow*)(gtkwb->window), pixbuf);
833 static void pidgin_whiteboard_rgb24_to_rgb48(int color_rgb, GdkColor *color)
835 color->red = (color_rgb >> 8) | 0xFF;
836 color->green = (color_rgb & 0xFF00) | 0xFF;
837 color->blue = ((color_rgb & 0xFF) << 8) | 0xFF;
840 static void
841 change_color_cb(GtkColorSelection *selection, PidginWhiteboard *gtkwb)
843 GdkColor color;
844 int old_size = 5;
845 int old_color = 0;
846 int new_color;
847 PurpleWhiteboard *wb = gtkwb->wb;
849 gtk_color_selection_get_current_color(selection, &color);
850 new_color = (color.red & 0xFF00) << 8;
851 new_color |= (color.green & 0xFF00);
852 new_color |= (color.blue & 0xFF00) >> 8;
854 purple_whiteboard_get_brush(wb, &old_size, &old_color);
855 purple_whiteboard_send_brush(wb, old_size, new_color);
858 static void color_selection_dialog_destroy(GtkWidget *w, PidginWhiteboard *gtkwb)
860 GtkWidget *dialog = g_object_get_data(G_OBJECT(gtkwb->window), "colour-dialog");
861 gtk_widget_destroy(dialog);
862 g_object_set_data(G_OBJECT(gtkwb->window), "colour-dialog", NULL);
865 static void color_select_dialog(GtkWidget *widget, PidginWhiteboard *gtkwb)
867 GdkColor color;
868 GtkColorSelectionDialog *dialog;
870 dialog = (GtkColorSelectionDialog *)gtk_color_selection_dialog_new(_("Select color"));
871 g_object_set_data(G_OBJECT(gtkwb->window), "colour-dialog", dialog);
873 g_signal_connect(G_OBJECT(dialog->colorsel), "color-changed",
874 G_CALLBACK(change_color_cb), gtkwb);
876 gtk_widget_destroy(dialog->cancel_button);
877 gtk_widget_destroy(dialog->help_button);
879 g_signal_connect(G_OBJECT(dialog->ok_button), "clicked",
880 G_CALLBACK(color_selection_dialog_destroy), gtkwb);
882 gtk_color_selection_set_has_palette(GTK_COLOR_SELECTION(dialog->colorsel), TRUE);
884 pidgin_whiteboard_rgb24_to_rgb48(gtkwb->brush_color, &color);
885 gtk_color_selection_set_current_color(GTK_COLOR_SELECTION(dialog->colorsel), &color);
887 gtk_widget_show_all(GTK_WIDGET(dialog));