| 138 |
130 |
| 139 struct _gaim_gtk_blist_node { |
131 struct _gaim_gtk_blist_node { |
| 140 GtkTreeRowReference *row; |
132 GtkTreeRowReference *row; |
| 141 gboolean contact_expanded; |
133 gboolean contact_expanded; |
| 142 }; |
134 }; |
| 143 |
|
| 144 |
|
| 145 #ifdef WANT_DROP_SHADOW |
|
| 146 /**************************** Weird drop shadow stuff *******************/ |
|
| 147 /* This is based on a patch for drop shadows in GTK+ menus available at |
|
| 148 * http://www.xfce.org/gtkmenu-shadow/ |
|
| 149 */ |
|
| 150 |
|
| 151 enum side { |
|
| 152 EAST_SIDE, |
|
| 153 SOUTH_SIDE |
|
| 154 }; |
|
| 155 |
|
| 156 static const double shadow_strip_l[5] = { |
|
| 157 .937, .831, .670, .478, .180 |
|
| 158 }; |
|
| 159 |
|
| 160 static const double bottom_left_corner[25] = { |
|
| 161 1.00, .682, .423, .333, .258, |
|
| 162 1.00, .898, .800, .682, .584, |
|
| 163 1.00, .937, .874, .800, .737, |
|
| 164 1.00, .968, .937, .898, .866, |
|
| 165 1.00, .988, .976, .960, .945 |
|
| 166 }; |
|
| 167 |
|
| 168 static const double bottom_right_corner[25] = { |
|
| 169 .258, .584, .737, .866, .945, |
|
| 170 .584, .682, .800, .898, .960, |
|
| 171 .737, .800, .874, .937, .976, |
|
| 172 .866, .898, .937, .968, .988, |
|
| 173 .945, .960, .976, .988, .996 |
|
| 174 }; |
|
| 175 |
|
| 176 static const double top_right_corner[25] = { |
|
| 177 1.00, 1.00, 1.00, 1.00, 1.00, |
|
| 178 .686, .898, .937, .968, .988, |
|
| 179 .423, .803, .874, .937, .976, |
|
| 180 .333, .686, .800, .898, .960, |
|
| 181 .258, .584, .737, .866, .945 |
|
| 182 }; |
|
| 183 |
|
| 184 static const double top_left_corner[25] = { |
|
| 185 .988, .968, .937, .898, .498, |
|
| 186 .976, .937, .874, .803, .423, |
|
| 187 .960, .898, .800, .686, .333, |
|
| 188 .945, .866, .737, .584, .258, |
|
| 189 .941, .847, .698, .521, .215 |
|
| 190 }; |
|
| 191 |
|
| 192 |
|
| 193 static gboolean xcomposite_is_present() |
|
| 194 { |
|
| 195 static gboolean result = FALSE; |
|
| 196 #ifndef _WIN32 |
|
| 197 static gboolean known = FALSE; |
|
| 198 int i, j, k; |
|
| 199 |
|
| 200 if (!known) { |
|
| 201 /* I don't actually care about versions/etc. */ |
|
| 202 if (XQueryExtension(GDK_DISPLAY(), "Composite", &i, &j, &k) == True) |
|
| 203 result = TRUE; |
|
| 204 known = TRUE; |
|
| 205 } |
|
| 206 #endif |
|
| 207 |
|
| 208 return result; |
|
| 209 } |
|
| 210 |
|
| 211 static GdkPixbuf * |
|
| 212 get_pixbuf(GtkWidget *menu, int x, int y, int width, int height) |
|
| 213 { |
|
| 214 GdkPixbuf *dest, *src; |
|
| 215 GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET(menu)); |
|
| 216 GdkWindow *root = gdk_screen_get_root_window (screen); |
|
| 217 gint screen_height = gdk_screen_get_height (screen); |
|
| 218 gint screen_width = gdk_screen_get_width (screen); |
|
| 219 gint original_width = width; |
|
| 220 gint original_height = height; |
|
| 221 |
|
| 222 if (x < 0) { |
|
| 223 width += x; |
|
| 224 x = 0; |
|
| 225 } |
|
| 226 |
|
| 227 if (y < 0) { |
|
| 228 height += y; |
|
| 229 y = 0; |
|
| 230 } |
|
| 231 |
|
| 232 if (x + width > screen_width) { |
|
| 233 width = screen_width - x; |
|
| 234 } |
|
| 235 |
|
| 236 if (y + height > screen_height) { |
|
| 237 height = screen_height - y; |
|
| 238 } |
|
| 239 |
|
| 240 if (width <= 0 || height <= 0) |
|
| 241 return NULL; |
|
| 242 |
|
| 243 dest = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, |
|
| 244 original_width, original_height); |
|
| 245 src = gdk_pixbuf_get_from_drawable(NULL, root, NULL, x, y, 0, 0, |
|
| 246 width, height); |
|
| 247 gdk_pixbuf_copy_area (src, 0, 0, width, height, dest, 0, 0); |
|
| 248 |
|
| 249 g_object_unref (G_OBJECT (src)); |
|
| 250 |
|
| 251 return dest; |
|
| 252 } |
|
| 253 |
|
| 254 static void |
|
| 255 shadow_paint(GaimGtkBuddyList *blist, GdkRectangle *area, enum side shadow) |
|
| 256 { |
|
| 257 gint width, height; |
|
| 258 GdkGC *gc = gtkblist->tipwindow->style->black_gc; |
|
| 259 |
|
| 260 switch (shadow) { |
|
| 261 case EAST_SIDE: |
|
| 262 if (gtkblist->east != NULL) { |
|
| 263 if (area) |
|
| 264 gdk_gc_set_clip_rectangle (gc, area); |
|
| 265 |
|
| 266 width = gdk_pixbuf_get_width (gtkblist->east); |
|
| 267 height = gdk_pixbuf_get_height (gtkblist->east); |
|
| 268 |
|
| 269 gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->east_shadow), gc, |
|
| 270 gtkblist->east, 0, 0, 0, 0, width, height, |
|
| 271 GDK_RGB_DITHER_NONE, 0, 0); |
|
| 272 |
|
| 273 if (area) |
|
| 274 gdk_gc_set_clip_rectangle (gc, NULL); |
|
| 275 } |
|
| 276 break; |
|
| 277 |
|
| 278 case SOUTH_SIDE: |
|
| 279 if (blist->south != NULL) { |
|
| 280 if (area) |
|
| 281 gdk_gc_set_clip_rectangle (gc, area); |
|
| 282 |
|
| 283 width = gdk_pixbuf_get_width (gtkblist->south); |
|
| 284 height = gdk_pixbuf_get_height (gtkblist->south); |
|
| 285 |
|
| 286 gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->south_shadow), gc, |
|
| 287 gtkblist->south, 0, 0, 0, 0, width, height, |
|
| 288 GDK_RGB_DITHER_NONE, 0, 0); |
|
| 289 |
|
| 290 if (area) |
|
| 291 gdk_gc_set_clip_rectangle (gc, NULL); |
|
| 292 } |
|
| 293 break; |
|
| 294 } |
|
| 295 } |
|
| 296 |
|
| 297 static void |
|
| 298 pixbuf_add_shadow (GdkPixbuf *pb, enum side shadow) |
|
| 299 { |
|
| 300 gint width, rowstride, height; |
|
| 301 gint i; |
|
| 302 guchar *pixels, *p; |
|
| 303 |
|
| 304 width = gdk_pixbuf_get_width (pb); |
|
| 305 height = gdk_pixbuf_get_height (pb); |
|
| 306 rowstride = gdk_pixbuf_get_rowstride (pb); |
|
| 307 pixels = gdk_pixbuf_get_pixels (pb); |
|
| 308 |
|
| 309 switch (shadow) { |
|
| 310 case EAST_SIDE: |
|
| 311 if (height > 5) { |
|
| 312 for (i = 0; i < width; i++) { |
|
| 313 gint j, k; |
|
| 314 |
|
| 315 p = pixels + (i * rowstride); |
|
| 316 for (j = 0, k = 0; j < 3 * width; j += 3, k++) { |
|
| 317 p[j] = (guchar) (p[j] * top_right_corner [i * width + k]); |
|
| 318 p[j + 1] = (guchar) (p[j + 1] * top_right_corner [i * width + k]); |
|
| 319 p[j + 2] = (guchar) (p[j + 2] * top_right_corner [i * width + k]); |
|
| 320 } |
|
| 321 } |
|
| 322 |
|
| 323 i = 5; |
|
| 324 } else { |
|
| 325 i = 0; |
|
| 326 } |
|
| 327 |
|
| 328 for (; i < height; i++) { |
|
| 329 gint j, k; |
|
| 330 |
|
| 331 p = pixels + (i * rowstride); |
|
| 332 for (j = 0, k = 0; j < 3 * width; j += 3, k++) { |
|
| 333 p[j] = (guchar) (p[j] * shadow_strip_l[width - 1 - k]); |
|
| 334 p[j + 1] = (guchar) (p[j + 1] * shadow_strip_l[width - 1 - k]); |
|
| 335 p[j + 2] = (guchar) (p[j + 2] * shadow_strip_l[width - 1 - k]); |
|
| 336 } |
|
| 337 } |
|
| 338 break; |
|
| 339 |
|
| 340 case SOUTH_SIDE: |
|
| 341 for (i = 0; i < height; i++) { |
|
| 342 gint j, k; |
|
| 343 |
|
| 344 p = pixels + (i * rowstride); |
|
| 345 for (j = 0, k = 0; j < 3 * height; j += 3, k++) { |
|
| 346 p[j] = (guchar) (p[j] * bottom_left_corner[i * height + k]); |
|
| 347 p[j + 1] = (guchar) (p[j + 1] * bottom_left_corner[i * height + k]); |
|
| 348 p[j + 2] = (guchar) (p[j + 2] * bottom_left_corner[i * height + k]); |
|
| 349 } |
|
| 350 |
|
| 351 p = pixels + (i * rowstride) + 3 * height; |
|
| 352 for (j = 0, k = 0; j < (width * 3) - (6 * height); j += 3, k++) { |
|
| 353 p[j] = (guchar) (p[j] * bottom_right_corner [i * height]); |
|
| 354 p[j + 1] = (guchar) (p[j + 1] * bottom_right_corner [i * height]); |
|
| 355 p[j + 2] = (guchar) (p[j + 2] * bottom_right_corner [i * height]); |
|
| 356 } |
|
| 357 |
|
| 358 p = pixels + (i * rowstride) + ((width * 3) - (3 * height)); |
|
| 359 for (j = 0, k = 0; j < 3 * height; j += 3, k++) { |
|
| 360 p[j] = (guchar) (p[j] * bottom_right_corner[i * height + k]); |
|
| 361 p[j + 1] = (guchar) (p[j + 1] * bottom_right_corner[i * height + k]); |
|
| 362 p[j + 2] = (guchar) (p[j + 2] * bottom_right_corner[i * height + k]); |
|
| 363 } |
|
| 364 } |
|
| 365 break; |
|
| 366 } |
|
| 367 } |
|
| 368 |
|
| 369 static gboolean |
|
| 370 map_shadow_windows (gpointer data) |
|
| 371 { |
|
| 372 GaimGtkBuddyList *blist = (GaimGtkBuddyList*)data; |
|
| 373 GtkWidget *widget = blist->tipwindow; |
|
| 374 GdkPixbuf *pixbuf; |
|
| 375 int x, y; |
|
| 376 |
|
| 377 gtk_window_get_position(GTK_WINDOW(widget), &x, &y); |
|
| 378 pixbuf = get_pixbuf(widget, |
|
| 379 x + widget->allocation.width, y, |
|
| 380 5, widget->allocation.height + 5); |
|
| 381 if (pixbuf != NULL) |
|
| 382 { |
|
| 383 pixbuf_add_shadow (pixbuf, EAST_SIDE); |
|
| 384 if (blist->east != NULL) |
|
| 385 { |
|
| 386 g_object_unref (G_OBJECT (blist->east)); |
|
| 387 } |
|
| 388 blist->east = pixbuf; |
|
| 389 } |
|
| 390 |
|
| 391 pixbuf = get_pixbuf (widget, |
|
| 392 x, y + widget->allocation.height, |
|
| 393 widget->allocation.width + 5, 5); |
|
| 394 if (pixbuf != NULL) |
|
| 395 { |
|
| 396 pixbuf_add_shadow (pixbuf, SOUTH_SIDE); |
|
| 397 if (blist->south != NULL) |
|
| 398 { |
|
| 399 g_object_unref (G_OBJECT (blist->south)); |
|
| 400 } |
|
| 401 blist->south = pixbuf; |
|
| 402 } |
|
| 403 |
|
| 404 gdk_window_move_resize (blist->east_shadow, |
|
| 405 x + widget->allocation.width, MAX(0,y), |
|
| 406 5, MIN(widget->allocation.height, gdk_screen_height())); |
|
| 407 |
|
| 408 gdk_window_move_resize (blist->south_shadow, |
|
| 409 MAX(0,x), y + widget->allocation.height, |
|
| 410 MIN(widget->allocation.width + 5, gdk_screen_width()), 5); |
|
| 411 |
|
| 412 gdk_window_show (blist->east_shadow); |
|
| 413 gdk_window_show (blist->south_shadow); |
|
| 414 shadow_paint(blist, NULL, EAST_SIDE); |
|
| 415 shadow_paint(blist, NULL, SOUTH_SIDE); |
|
| 416 |
|
| 417 return FALSE; |
|
| 418 } |
|
| 419 |
|
| 420 /**************** END WEIRD DROP SHADOW STUFF ***********************************/ |
|
| 421 #endif /* ifdef WANT_DROP_SHADOW */ |
|
| 422 |
135 |
| 423 |
136 |
| 424 static char dim_grey_string[8] = ""; |
137 static char dim_grey_string[8] = ""; |
| 425 static char *dim_grey() |
138 static char *dim_grey() |
| 426 { |
139 { |
| 2446 gtk_window_set_resizable(GTK_WINDOW(gtkblist->tipwindow), FALSE); |
2137 gtk_window_set_resizable(GTK_WINDOW(gtkblist->tipwindow), FALSE); |
| 2447 gtk_widget_set_name(gtkblist->tipwindow, "gtk-tooltips"); |
2138 gtk_widget_set_name(gtkblist->tipwindow, "gtk-tooltips"); |
| 2448 g_signal_connect(G_OBJECT(gtkblist->tipwindow), "expose_event", |
2139 g_signal_connect(G_OBJECT(gtkblist->tipwindow), "expose_event", |
| 2449 G_CALLBACK(gaim_gtk_blist_paint_tip), node); |
2140 G_CALLBACK(gaim_gtk_blist_paint_tip), node); |
| 2450 gtk_widget_ensure_style (gtkblist->tipwindow); |
2141 gtk_widget_ensure_style (gtkblist->tipwindow); |
| 2451 |
|
| 2452 #ifdef WANT_DROP_SHADOW |
|
| 2453 if (!xcomposite_is_present()) { |
|
| 2454 attr.window_type = GDK_WINDOW_TEMP; |
|
| 2455 attr.override_redirect = TRUE; |
|
| 2456 attr.x = gtkblist->tipwindow->allocation.x; |
|
| 2457 attr.y = gtkblist->tipwindow->allocation.y; |
|
| 2458 attr.width = gtkblist->tipwindow->allocation.width; |
|
| 2459 attr.height = gtkblist->tipwindow->allocation.height; |
|
| 2460 attr.wclass = GDK_INPUT_OUTPUT; |
|
| 2461 attr.visual = gtk_widget_get_visual (gtkblist->window); |
|
| 2462 attr.colormap = gtk_widget_get_colormap (gtkblist->window); |
|
| 2463 |
|
| 2464 attr.event_mask = gtk_widget_get_events (gtkblist->tipwindow); |
|
| 2465 |
|
| 2466 attr.event_mask |= (GDK_EXPOSURE_MASK | GDK_KEY_PRESS_MASK | |
|
| 2467 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK ); |
|
| 2468 gtkblist->east_shadow = gdk_window_new(gtk_widget_get_root_window(gtkblist->tipwindow), &attr, |
|
| 2469 GDK_WA_NOREDIR | GDK_WA_VISUAL | GDK_WA_COLORMAP); |
|
| 2470 gdk_window_set_user_data (gtkblist->east_shadow, gtkblist->tipwindow); |
|
| 2471 gdk_window_set_back_pixmap (gtkblist->east_shadow, NULL, FALSE); |
|
| 2472 |
|
| 2473 gtkblist->south_shadow = gdk_window_new(gtk_widget_get_root_window(gtkblist->tipwindow), &attr, |
|
| 2474 GDK_WA_NOREDIR | GDK_WA_VISUAL | GDK_WA_COLORMAP); |
|
| 2475 gdk_window_set_user_data (gtkblist->south_shadow, gtkblist->tipwindow); |
|
| 2476 gdk_window_set_back_pixmap (gtkblist->south_shadow, NULL, FALSE); |
|
| 2477 } |
|
| 2478 #endif /* ifdef WANT_DROP_SHADOW */ |
|
| 2479 |
2142 |
| 2480 layout = gtk_widget_create_pango_layout (gtkblist->tipwindow, NULL); |
2143 layout = gtk_widget_create_pango_layout (gtkblist->tipwindow, NULL); |
| 2481 pango_layout_set_wrap(layout, PANGO_WRAP_WORD); |
2144 pango_layout_set_wrap(layout, PANGO_WRAP_WORD); |
| 2482 pango_layout_set_width(layout, 300000); |
2145 pango_layout_set_width(layout, 300000); |
| 2483 pango_layout_set_markup(layout, gtkblist->tooltiptext, strlen(gtkblist->tooltiptext)); |
2146 pango_layout_set_markup(layout, gtkblist->tooltiptext, strlen(gtkblist->tooltiptext)); |