Merged pidgin/main into default
[pidgin-git.git] / pidgin / gtkdnd-hints.c
blobfa3f206767b1307a5972bb7f98d4dbf4678895cf
1 /* pidgin
3 * Pidgin is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
5 * source distribution.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or(at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301, USA.
22 #include "gtkdnd-hints.h"
24 #include "internal.h"
26 #include <gdk/gdk.h>
27 #include <gdk-pixbuf/gdk-pixbuf.h>
29 #include "gtk3compat.h"
31 typedef struct
33 GtkWidget *widget;
34 gchar *filename;
35 gint ox;
36 gint oy;
38 } HintWindowInfo;
41 * Info about each hint widget. See PidginDndHintWindowId enum.
43 static HintWindowInfo hint_windows[] = {
44 { NULL, "arrow-up.xpm", -13/2, 0 },
45 { NULL, "arrow-down.xpm", -13/2, -16 },
46 { NULL, "arrow-left.xpm", 0, -13/2 },
47 { NULL, "arrow-right.xpm", -16, -13/2 },
48 { NULL, NULL, 0, 0 }
51 static void
52 dnd_hints_realized_cb(GtkWidget *window, GtkWidget *pix)
54 GdkPixbuf *pixbuf;
55 cairo_surface_t *surface;
56 cairo_region_t *region;
57 cairo_t *cr;
59 pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(pix));
61 surface = cairo_image_surface_create(CAIRO_FORMAT_A1,
62 gdk_pixbuf_get_width(pixbuf),
63 gdk_pixbuf_get_height(pixbuf));
65 cr = cairo_create(surface);
66 gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
67 cairo_paint(cr);
68 cairo_destroy(cr);
70 region = gdk_cairo_region_create_from_surface(surface);
71 gtk_widget_shape_combine_region(window, region);
72 cairo_region_destroy(region);
74 cairo_surface_destroy(surface);
77 static GtkWidget *
78 dnd_hints_init_window(const gchar *fname)
80 GdkPixbuf *pixbuf;
81 GtkWidget *pix;
82 GtkWidget *win;
84 pixbuf = gdk_pixbuf_new_from_file(fname, NULL);
85 g_return_val_if_fail(pixbuf, NULL);
87 win = gtk_window_new(GTK_WINDOW_POPUP);
88 pix = gtk_image_new_from_pixbuf(pixbuf);
89 gtk_container_add(GTK_CONTAINER(win), pix);
90 gtk_widget_show_all(pix);
92 g_object_unref(G_OBJECT(pixbuf));
94 g_signal_connect(G_OBJECT(win), "realize",
95 G_CALLBACK(dnd_hints_realized_cb), pix);
97 return win;
100 static void
101 get_widget_coords(GtkWidget *w, gint *x1, gint *y1, gint *x2, gint *y2)
103 gint ox, oy, width, height;
104 GtkWidget *parent = gtk_widget_get_parent(w);
106 if (parent && gtk_widget_get_window(parent) == gtk_widget_get_window(w))
108 GtkAllocation allocation;
110 gtk_widget_get_allocation(w, &allocation);
111 get_widget_coords(parent, &ox, &oy, NULL, NULL);
112 height = allocation.height;
113 width = allocation.width;
115 else
117 GdkWindow *win = gtk_widget_get_window(w);
118 gdk_window_get_origin(win, &ox, &oy);
119 width = gdk_window_get_width(win);
120 height = gdk_window_get_height(win);
123 if (x1) *x1 = ox;
124 if (y1) *y1 = oy;
125 if (x2) *x2 = ox + width;
126 if (y2) *y2 = oy + height;
129 static void
130 dnd_hints_init(void)
132 static gboolean done = FALSE;
133 gint i;
135 if (done)
136 return;
138 done = TRUE;
140 for (i = 0; hint_windows[i].filename != NULL; i++) {
141 gchar *fname;
143 fname = g_build_filename(PURPLE_DATADIR, "pixmaps", "pidgin",
144 hint_windows[i].filename, NULL);
146 hint_windows[i].widget = dnd_hints_init_window(fname);
148 g_free(fname);
152 void
153 pidgin_dnd_hints_hide_all(void)
155 gint i;
157 for (i = 0; hint_windows[i].filename != NULL; i++)
158 pidgin_dnd_hints_hide(i);
161 void
162 pidgin_dnd_hints_hide(PidginDndHintWindowId i)
164 GtkWidget *w = hint_windows[i].widget;
166 if (w && GTK_IS_WIDGET(w))
167 gtk_widget_hide(w);
170 void
171 pidgin_dnd_hints_show(PidginDndHintWindowId id, gint x, gint y)
173 GtkWidget *w;
175 dnd_hints_init();
177 w = hint_windows[id].widget;
179 if (w && GTK_IS_WIDGET(w))
181 gtk_window_move(GTK_WINDOW(w), hint_windows[id].ox + x,
182 hint_windows[id].oy + y);
183 gtk_widget_show(w);
187 void
188 pidgin_dnd_hints_show_relative(PidginDndHintWindowId id, GtkWidget *widget,
189 PidginDndHintPosition horiz, PidginDndHintPosition vert)
191 gint x1, x2, y1, y2;
192 gint x = 0, y = 0;
193 GtkAllocation allocation;
195 gtk_widget_get_allocation(widget, &allocation);
197 get_widget_coords(widget, &x1, &y1, &x2, &y2);
198 x1 += allocation.x; x2 += allocation.x;
199 y1 += allocation.y; y2 += allocation.y;
201 switch (horiz)
203 case HINT_POSITION_RIGHT: x = x2; break;
204 case HINT_POSITION_LEFT: x = x1; break;
205 case HINT_POSITION_CENTER: x = (x1 + x2) / 2; break;
206 default:
207 /* should not happen */
208 g_warning("Invalid parameter to pidgin_dnd_hints_show_relative");
209 break;
212 switch (vert)
214 case HINT_POSITION_TOP: y = y1; break;
215 case HINT_POSITION_BOTTOM: y = y2; break;
216 case HINT_POSITION_CENTER: y = (y1 + y2) / 2; break;
217 default:
218 /* should not happen */
219 g_warning("Invalid parameter to pidgin_dnd_hints_show_relative");
220 break;
223 pidgin_dnd_hints_show(id, x, y);