Mercurial > pidgin.yaz
diff src/gtkstatusbox.c @ 14133:31d33e7bc0e6
[gaim-migrate @ 16775]
A global buddy icon selector in the statusbox.
This is done totally in the GTK+ UI; the core still sees a buddy icon as
belonging to an account.
Per-account icons can override the global one in Modify Account.
There are some caching issues to work out, still.
committer: Tailor Script <tailor@pidgin.im>
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Tue, 15 Aug 2006 23:25:29 +0000 |
parents | a8a033a89ee0 |
children | 4006d3dc2871 |
line wrap: on
line diff
--- a/src/gtkstatusbox.c Tue Aug 15 20:23:58 2006 +0000 +++ b/src/gtkstatusbox.c Tue Aug 15 23:25:29 2006 +0000 @@ -77,6 +77,8 @@ static gboolean gtk_gaim_status_box_expose_event (GtkWidget *widget, GdkEventExpose *event); static void gtk_gaim_status_box_forall (GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data); +static void do_colorshift (GdkPixbuf *dest, GdkPixbuf *src, int shift); + static void (*combo_box_size_request)(GtkWidget *widget, GtkRequisition *requisition); static void (*combo_box_size_allocate)(GtkWidget *widget, GtkAllocation *allocation); static void (*combo_box_forall) (GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data); @@ -260,6 +262,17 @@ gaim_signals_disconnect_by_handle(statusbox); gaim_prefs_disconnect_by_handle(statusbox); + gdk_cursor_unref(statusbox->hand_cursor); + gdk_cursor_unref(statusbox->arrow_cursor); + + g_object_unref(G_OBJECT(statusbox->buddy_icon)); + g_object_unref(G_OBJECT(statusbox->buddy_icon_hover)); + + if (statusbox->buddy_icon_sel) + gtk_widget_destroy(statusbox->buddy_icon_sel); + + g_free(statusbox->buddy_icon_path); + G_OBJECT_CLASS(parent_class)->finalize(obj); } @@ -907,6 +920,55 @@ } static void +icon_choose_cb(const char *filename, GtkGaimStatusBox *box) +{ + if (filename) { + GList *accounts; + for (accounts = gaim_accounts_get_all(); accounts != NULL; accounts = accounts->next) { + GaimAccount *account = accounts->data; + if (gaim_account_get_ui_bool(account, GAIM_GTK_UI, "use-global-buddy-icon", TRUE)) { + char *icon = gaim_gtk_convert_buddy_icon(gaim_find_prpl(gaim_account_get_protocol_id(account)), + filename); + gaim_account_set_buddy_icon(account, icon); + g_free(icon); + } + } + gtk_gaim_status_box_set_buddy_icon(box, filename); + } + + box->buddy_icon_sel = NULL; +} + +static gboolean +icon_box_press_cb(GtkWidget *widget, GdkEventButton *event, GtkGaimStatusBox *box) +{ + if (box->buddy_icon_sel) { + gtk_window_present(GTK_WINDOW(box->buddy_icon_sel)); + return FALSE; + } + + GtkWidget *filesel = gaim_gtk_buddy_icon_chooser_new(NULL, icon_choose_cb, box); + gtk_widget_show_all(filesel); + return FALSE; +} + +static gboolean +icon_box_enter_cb(GtkWidget *widget, GdkEventCrossing *event, GtkGaimStatusBox *box) +{ + gdk_window_set_cursor(widget->window, box->hand_cursor); + gtk_image_set_from_pixbuf(box->icon, box->buddy_icon_hover); + return FALSE; +} + +static gboolean +icon_box_leave_cb(GtkWidget *widget, GdkEventCrossing *event, GtkGaimStatusBox *box) +{ + gdk_window_set_cursor(widget->window, box->arrow_cursor); + gtk_image_set_from_pixbuf(box->icon, box->buddy_icon) ; + return FALSE; +} + +static void gtk_gaim_status_box_init (GtkGaimStatusBox *status_box) { GtkCellRenderer *text_rend; @@ -922,6 +984,18 @@ status_box->vsep = gtk_vseparator_new(); status_box->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); + status_box->buddy_icon = gdk_pixbuf_new_from_file("/home/seanegan/p1120233.jpg", NULL); + status_box->icon = gtk_image_new_from_pixbuf(status_box->buddy_icon); + status_box->icon_box = gtk_event_box_new(); + status_box->hand_cursor = gdk_cursor_new (GDK_HAND2); + status_box->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR); + + g_signal_connect(G_OBJECT(status_box->icon_box), "enter-notify-event", G_CALLBACK(icon_box_enter_cb), status_box); + g_signal_connect(G_OBJECT(status_box->icon_box), "leave-notify-event", G_CALLBACK(icon_box_leave_cb), status_box); + g_signal_connect(G_OBJECT(status_box->icon_box), "button-press-event", G_CALLBACK(icon_box_press_cb), status_box); + + gtk_container_add(GTK_CONTAINER(status_box->icon_box), status_box->icon); + status_box->store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_INT, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); status_box->dropdown_store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_INT, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); gtk_combo_box_set_model(GTK_COMBO_BOX(status_box), GTK_TREE_MODEL(status_box->dropdown_store)); @@ -934,6 +1008,7 @@ gtk_box_pack_start(GTK_BOX(status_box->hbox), status_box->vsep, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(status_box->hbox), status_box->arrow, FALSE, FALSE, 0); gtk_widget_show_all(status_box->toggle_button); + gtk_widget_show_all(status_box->icon_box); #if GTK_CHECK_VERSION(2,4,0) gtk_button_set_focus_on_click(GTK_BUTTON(status_box->toggle_button), FALSE); #endif @@ -984,6 +1059,7 @@ #endif gtk_widget_set_parent(status_box->vbox, GTK_WIDGET(status_box)); gtk_widget_set_parent(status_box->toggle_button, GTK_WIDGET(status_box)); + gtk_widget_set_parent(status_box->icon_box, GTK_WIDGET(status_box)); GTK_BIN(status_box)->child = status_box->toggle_button; gtk_box_pack_start(GTK_BOX(status_box->vbox), status_box->sw, TRUE, TRUE, 0); @@ -1024,14 +1100,58 @@ requisition->height += box_req.height + 3; requisition->width = 1; + + +} + +/* From gnome-panel */ +static void +do_colorshift (GdkPixbuf *dest, GdkPixbuf *src, int shift) +{ + gint i, j; + gint width, height, has_alpha, srcrowstride, destrowstride; + guchar *target_pixels; + guchar *original_pixels; + guchar *pixsrc; + guchar *pixdest; + int val; + guchar r,g,b; + + has_alpha = gdk_pixbuf_get_has_alpha (src); + width = gdk_pixbuf_get_width (src); + height = gdk_pixbuf_get_height (src); + srcrowstride = gdk_pixbuf_get_rowstride (src); + destrowstride = gdk_pixbuf_get_rowstride (dest); + target_pixels = gdk_pixbuf_get_pixels (dest); + original_pixels = gdk_pixbuf_get_pixels (src); + + for (i = 0; i < height; i++) { + pixdest = target_pixels + i*destrowstride; + pixsrc = original_pixels + i*srcrowstride; + for (j = 0; j < width; j++) { + r = *(pixsrc++); + g = *(pixsrc++); + b = *(pixsrc++); + val = r + shift; + *(pixdest++) = CLAMP(val, 0, 255); + val = g + shift; + *(pixdest++) = CLAMP(val, 0, 255); + val = b + shift; + *(pixdest++) = CLAMP(val, 0, 255); + if (has_alpha) + *(pixdest++) = *(pixsrc++); + } + } } static void gtk_gaim_status_box_size_allocate(GtkWidget *widget, - GtkAllocation *allocation) + GtkAllocation *allocation) { + GtkGaimStatusBox *status_box = GTK_GAIM_STATUS_BOX(widget); GtkRequisition req = {0,0}; - GtkAllocation parent_alc, box_alc; + GtkAllocation parent_alc, box_alc, icon_alc; + GdkPixbuf *scaled; combo_box_size_request(widget, &req); @@ -1043,7 +1163,28 @@ parent_alc = *allocation; parent_alc.height = MAX(1,req.height); parent_alc.y += 3; + parent_alc.width -= (parent_alc.height + 3); combo_box_size_allocate(widget, &parent_alc); + + icon_alc = *allocation; + icon_alc.height = MAX(1,req.height); + icon_alc.width = icon_alc.height; + icon_alc.x = allocation->width - icon_alc.width; + icon_alc.y += 3; + + if (status_box->icon_size != icon_alc.height) { + scaled = gdk_pixbuf_new_from_file_at_scale(status_box->buddy_icon_path, + icon_alc.height, icon_alc.width, FALSE, NULL); + status_box->buddy_icon_hover = gdk_pixbuf_copy(scaled); + do_colorshift(status_box->buddy_icon_hover, status_box->buddy_icon_hover, 30); + g_object_unref(status_box->buddy_icon); + status_box->buddy_icon = scaled; + gtk_image_set_from_pixbuf(status_box->icon, status_box->buddy_icon); + status_box->icon_size = icon_alc.height; + } + gtk_widget_size_allocate((GTK_GAIM_STATUS_BOX(widget))->icon_box, &icon_alc); + + gtk_widget_size_allocate((GTK_GAIM_STATUS_BOX(widget))->toggle_button, &parent_alc); widget->allocation = *allocation; } @@ -1055,6 +1196,7 @@ GtkGaimStatusBox *status_box = GTK_GAIM_STATUS_BOX(widget); gtk_container_propagate_expose(GTK_CONTAINER(widget), status_box->vbox, event); gtk_container_propagate_expose(GTK_CONTAINER(widget), status_box->toggle_button, event); + gtk_container_propagate_expose(GTK_CONTAINER(widget), status_box->icon_box, event); return FALSE; } @@ -1071,6 +1213,7 @@ (* callback) (status_box->vbox, callback_data); (* callback) (status_box->toggle_button, callback_data); (* callback) (status_box->arrow, callback_data); + (* callback) (status_box->icon_box, callback_data); } combo_box_forall(container, include_internals, callback, callback_data); @@ -1179,6 +1322,30 @@ } void +gtk_gaim_status_box_set_buddy_icon(GtkGaimStatusBox *box, const char *filename) +{ + GdkPixbuf *scaled; + g_free(box->buddy_icon_path); + box->buddy_icon_path = g_strdup(filename); + + scaled = gdk_pixbuf_new_from_file_at_scale(filename, + box->icon_size, box->icon_size, FALSE, NULL); + box->buddy_icon_hover = gdk_pixbuf_copy(scaled); + do_colorshift(box->buddy_icon_hover, box->buddy_icon_hover, 30); + g_object_unref(box->buddy_icon); + box->buddy_icon = scaled; + gtk_image_set_from_pixbuf(box->icon, box->buddy_icon); + + gaim_prefs_set_string("/gaim/gtk/accounts/buddyicon", filename); +} + +const char* +gtk_gaim_status_box_get_buddy_icon(GtkGaimStatusBox *box) +{ + return box->buddy_icon_path; +} + +void gtk_gaim_status_box_pulse_connecting(GtkGaimStatusBox *status_box) { if (!status_box)