|
2822
|
1 /*
|
|
|
2 * Audacious - a cross-platform multimedia player
|
|
|
3 * Copyright (c) 2007 Audacious development team.
|
|
|
4 *
|
|
|
5 * This program is free software; you can redistribute it and/or modify
|
|
|
6 * it under the terms of the GNU General Public License as published by
|
|
|
7 * the Free Software Foundation; either version 2 of the License, or
|
|
|
8 * (at your option) any later version.
|
|
|
9 *
|
|
|
10 * This program is distributed in the hope that it will be useful,
|
|
|
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
13 * GNU General Public License for more details.
|
|
|
14 *
|
|
|
15 * You should have received a copy of the GNU General Public License
|
|
|
16 * along with this program; if not, write to the Free Software
|
|
|
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
18 */
|
|
|
19
|
|
|
20 #include "widgetcore.h"
|
|
|
21 #include "audacious_pbutton.h"
|
|
|
22
|
|
|
23 #include <gtk/gtkmain.h>
|
|
|
24 #include <gtk/gtkmarshal.h>
|
|
|
25 #include <gtk/gtkimage.h>
|
|
|
26
|
|
|
27 #define AUDACIOUS_PBUTTON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), AUDACIOUS_TYPE_PBUTTON, AudaciousPButtonPrivate))
|
|
|
28 typedef struct _AudaciousPButtonPrivate AudaciousPButtonPrivate;
|
|
|
29
|
|
|
30 struct _AudaciousPButtonPrivate {
|
|
|
31 //Skinned part
|
|
|
32 GtkWidget *image;
|
|
|
33 GdkGC *gc;
|
|
|
34 gint x;
|
|
|
35 gint y;
|
|
|
36 gint w;
|
|
|
37 gint h;
|
|
|
38 SkinPixmapId skin_index1;
|
|
|
39 SkinPixmapId skin_index2;
|
|
|
40 GtkWidget *fixed;
|
|
|
41 };
|
|
|
42
|
|
|
43
|
|
|
44 static GtkBinClass *parent_class = NULL;
|
|
|
45 static void audacious_pbutton_class_init(AudaciousPButtonClass *klass);
|
|
|
46 static void audacious_pbutton_init(AudaciousPButton *button);
|
|
|
47 static GObject* audacious_pbutton_constructor(GType type, guint n_construct_properties, GObjectConstructParam *construct_params);
|
|
|
48 static void audacious_pbutton_destroy(GtkObject *object);
|
|
|
49 static void audacious_pbutton_realize(GtkWidget *widget);
|
|
|
50 static void audacious_pbutton_unrealize(GtkWidget *widget);
|
|
|
51 static void audacious_pbutton_map(GtkWidget *widget);
|
|
|
52 static void audacious_pbutton_unmap(GtkWidget *widget);
|
|
|
53 static gint audacious_pbutton_expose(GtkWidget *widget,GdkEventExpose *event);
|
|
|
54
|
|
|
55 static void audacious_pbutton_size_allocate(GtkWidget *widget, GtkAllocation *allocation);
|
|
|
56 static void audacious_pbutton_update_state(AudaciousPButton *button);
|
|
|
57
|
|
|
58 static guint button_signals[LAST_SIGNAL] = { 0 };
|
|
|
59 static gint audacious_pbutton_button_press(GtkWidget *widget, GdkEventButton *event);
|
|
|
60 static gint audacious_pbutton_button_release(GtkWidget *widget, GdkEventButton *event);
|
|
|
61 static void button_pressed(AudaciousPButton *button);
|
|
|
62 static void button_released(AudaciousPButton *button);
|
|
|
63 static void audacious_pbutton_add(GtkContainer *container, GtkWidget *widget);
|
|
|
64 static void audacious_pbutton_set_doublesize(AudaciousPButton *button);
|
|
|
65
|
|
|
66 static gint audacious_pbutton_enter_notify(GtkWidget *widget, GdkEventCrossing *event);
|
|
|
67 static gint audacious_pbutton_leave_notify(GtkWidget *widget, GdkEventCrossing *event);
|
|
|
68 static void audacious_pbutton_paint(AudaciousPButton *button);
|
|
|
69
|
|
|
70 GType audacious_pbutton_get_type (void) {
|
|
|
71 static GType button_type = 0;
|
|
|
72
|
|
|
73 if (!button_type) {
|
|
|
74 static const GTypeInfo button_info = {
|
|
|
75 sizeof (AudaciousPButtonClass),
|
|
|
76 NULL, /* base_init */
|
|
|
77 NULL, /* base_finalize */
|
|
|
78 (GClassInitFunc) audacious_pbutton_class_init,
|
|
|
79 NULL, /* class_finalize */
|
|
|
80 NULL, /* class_data */
|
|
|
81 sizeof (AudaciousPButton),
|
|
|
82 16, /* n_preallocs */
|
|
|
83 (GInstanceInitFunc) audacious_pbutton_init,
|
|
|
84 };
|
|
|
85
|
|
|
86 button_type = g_type_register_static (GTK_TYPE_BIN, "AudaciousPButton", &button_info, 0);
|
|
|
87 }
|
|
|
88 return button_type;
|
|
|
89 }
|
|
|
90
|
|
|
91 static void audacious_pbutton_class_init (AudaciousPButtonClass *klass) {
|
|
|
92 GObjectClass *gobject_class;
|
|
|
93 GtkObjectClass *object_class;
|
|
|
94 GtkWidgetClass *widget_class;
|
|
|
95 GtkContainerClass *container_class;
|
|
|
96
|
|
|
97 gobject_class = G_OBJECT_CLASS(klass);
|
|
|
98 object_class = (GtkObjectClass*)klass;
|
|
|
99 widget_class = (GtkWidgetClass*)klass;
|
|
|
100 container_class = (GtkContainerClass*)klass;
|
|
|
101
|
|
|
102 parent_class = g_type_class_peek_parent(klass);
|
|
|
103 gobject_class->constructor = audacious_pbutton_constructor;
|
|
|
104 object_class->destroy = audacious_pbutton_destroy;
|
|
|
105
|
|
|
106 widget_class->realize = audacious_pbutton_realize;
|
|
|
107 widget_class->unrealize = audacious_pbutton_unrealize;
|
|
|
108 widget_class->map = audacious_pbutton_map;
|
|
|
109 widget_class->unmap = audacious_pbutton_unmap;
|
|
|
110 widget_class->size_allocate = audacious_pbutton_size_allocate;
|
|
|
111 widget_class->expose_event = audacious_pbutton_expose;
|
|
|
112 widget_class->button_press_event = audacious_pbutton_button_press;
|
|
|
113 widget_class->button_release_event = audacious_pbutton_button_release;
|
|
|
114 widget_class->enter_notify_event = audacious_pbutton_enter_notify;
|
|
|
115 widget_class->leave_notify_event = audacious_pbutton_leave_notify;
|
|
|
116
|
|
|
117 container_class->add = audacious_pbutton_add;
|
|
|
118
|
|
|
119 klass->pressed = button_pressed;
|
|
|
120 klass->released = button_released;
|
|
|
121 klass->clicked = NULL;
|
|
|
122 klass->doubled = audacious_pbutton_set_doublesize;
|
|
|
123
|
|
|
124 button_signals[PRESSED] =
|
|
|
125 g_signal_new ("pressed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST,
|
|
|
126 G_STRUCT_OFFSET (AudaciousPButtonClass, pressed), NULL, NULL,
|
|
|
127 gtk_marshal_VOID__VOID, G_TYPE_NONE, 0);
|
|
|
128
|
|
|
129 button_signals[RELEASED] =
|
|
|
130 g_signal_new ("released", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST,
|
|
|
131 G_STRUCT_OFFSET (AudaciousPButtonClass, released), NULL, NULL,
|
|
|
132 gtk_marshal_VOID__VOID, G_TYPE_NONE, 0);
|
|
|
133
|
|
|
134 button_signals[CLICKED] =
|
|
|
135 g_signal_new ("clicked", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
|
|
|
136 G_STRUCT_OFFSET (AudaciousPButtonClass, clicked), NULL, NULL,
|
|
|
137 gtk_marshal_VOID__VOID, G_TYPE_NONE, 0);
|
|
|
138
|
|
|
139 button_signals[DOUBLED] =
|
|
|
140 g_signal_new ("set-double-size", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
|
|
|
141 G_STRUCT_OFFSET (AudaciousPButtonClass, doubled), NULL, NULL,
|
|
|
142 gtk_marshal_VOID__VOID, G_TYPE_NONE, 0);
|
|
|
143
|
|
|
144 g_type_class_add_private (gobject_class, sizeof (AudaciousPButtonPrivate));
|
|
|
145 }
|
|
|
146
|
|
|
147 static void audacious_pbutton_init (AudaciousPButton *button) {
|
|
|
148 AudaciousPButtonPrivate *priv = AUDACIOUS_PBUTTON_GET_PRIVATE (button);
|
|
|
149 priv->image = gtk_image_new();
|
|
|
150 g_object_set (priv->image, "visible", TRUE, NULL);
|
|
|
151 gtk_container_add(GTK_CONTAINER(GTK_WIDGET(button)), priv->image);
|
|
|
152
|
|
|
153 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_FOCUS);
|
|
|
154 GTK_WIDGET_SET_FLAGS (button, GTK_NO_WINDOW);
|
|
|
155 }
|
|
|
156
|
|
|
157 static void audacious_pbutton_destroy (GtkObject *object) {
|
|
|
158 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
|
|
|
159 }
|
|
|
160
|
|
|
161 static GObject* audacious_pbutton_constructor(GType type, guint n_construct_properties, GObjectConstructParam *construct_params) {
|
|
|
162 GObject *object = (*G_OBJECT_CLASS (parent_class)->constructor)(type, n_construct_properties, construct_params);
|
|
|
163
|
|
|
164 return object;
|
|
|
165 }
|
|
|
166
|
|
|
167 static void audacious_pbutton_realize (GtkWidget *widget) {
|
|
|
168 AudaciousPButton *button = AUDACIOUS_PBUTTON (widget);
|
|
|
169 GdkWindowAttr attrib;
|
|
|
170
|
|
|
171 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
|
|
|
172
|
|
|
173 attrib.window_type = GDK_WINDOW_CHILD;
|
|
|
174 attrib.x = widget->allocation.x;
|
|
|
175 attrib.y = widget->allocation.y;
|
|
|
176 attrib.width = widget->allocation.width;
|
|
|
177 attrib.height = widget->allocation.height;
|
|
|
178 attrib.wclass = GDK_INPUT_ONLY;
|
|
|
179 attrib.event_mask = gtk_widget_get_events (widget);
|
|
|
180 attrib.event_mask |= (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
|
|
|
181
|
|
|
182 widget->window = gtk_widget_get_parent_window(widget);
|
|
|
183 g_object_ref(widget->window);
|
|
|
184
|
|
|
185 button->event_window = gdk_window_new(gtk_widget_get_parent_window(widget), &attrib, GDK_WA_X | GDK_WA_Y);
|
|
|
186 gdk_window_set_user_data (button->event_window, button);
|
|
|
187
|
|
|
188 audacious_pbutton_paint(button);
|
|
|
189 }
|
|
|
190
|
|
|
191 static void audacious_pbutton_unrealize(GtkWidget *widget) {
|
|
|
192 AudaciousPButton *button = AUDACIOUS_PBUTTON (widget);
|
|
|
193
|
|
|
194 if (button->event_window) {
|
|
|
195 gdk_window_set_user_data (button->event_window, NULL);
|
|
|
196 gdk_window_destroy (button->event_window);
|
|
|
197 button->event_window = NULL;
|
|
|
198 }
|
|
|
199
|
|
|
200 GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
|
|
|
201 }
|
|
|
202
|
|
|
203 static void audacious_pbutton_map(GtkWidget *widget) {
|
|
|
204 AudaciousPButton *button = AUDACIOUS_PBUTTON (widget);
|
|
|
205 g_return_if_fail (AUDACIOUS_IS_PBUTTON (widget));
|
|
|
206 GTK_WIDGET_CLASS (parent_class)->map(widget);
|
|
|
207 gdk_window_show (button->event_window);
|
|
|
208 }
|
|
|
209
|
|
|
210 static void audacious_pbutton_unmap (GtkWidget *widget) {
|
|
|
211 AudaciousPButton *button = AUDACIOUS_PBUTTON (widget);
|
|
|
212 g_return_if_fail (AUDACIOUS_IS_PBUTTON(widget));
|
|
|
213
|
|
|
214 if (button->event_window)
|
|
|
215 gdk_window_hide (button->event_window);
|
|
|
216
|
|
|
217 GTK_WIDGET_CLASS (parent_class)->unmap (widget);
|
|
|
218 }
|
|
|
219
|
|
|
220 static gboolean audacious_pbutton_expose(GtkWidget *widget, GdkEventExpose *event) {
|
|
|
221 if (GTK_WIDGET_DRAWABLE (widget))
|
|
|
222 (*GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
|
|
|
223
|
|
|
224 return FALSE;
|
|
|
225 }
|
|
|
226
|
|
|
227 GtkWidget* audacious_pbutton_new () {
|
|
|
228 return g_object_new (AUDACIOUS_TYPE_PBUTTON, NULL);
|
|
|
229 }
|
|
|
230
|
|
|
231 void audacious_pbutton_setup(GtkWidget *button, GtkWidget *fixed, GdkPixmap *parent, GdkGC *gc, gint x, gint y, gint w, gint h, gint nx, gint ny, gint px, gint py, SkinPixmapId si) {
|
|
|
232
|
|
|
233 AudaciousPButton *pbutton = AUDACIOUS_PBUTTON(button);
|
|
|
234 AudaciousPButtonPrivate *priv = AUDACIOUS_PBUTTON_GET_PRIVATE(pbutton);
|
|
|
235 priv->gc = gc;
|
|
|
236 priv->w = w;
|
|
|
237 priv->h = h;
|
|
|
238 pbutton->x = x;
|
|
|
239 pbutton->y = y;
|
|
|
240 pbutton->nx = nx;
|
|
|
241 pbutton->ny = ny;
|
|
|
242 pbutton->px = px;
|
|
|
243 pbutton->py = py;
|
|
|
244 priv->skin_index1 = si;
|
|
|
245 priv->skin_index2 = si;
|
|
|
246 priv->fixed = fixed;
|
|
|
247
|
|
|
248 gtk_widget_set_size_request(button, priv->w, priv->h);
|
|
|
249 gtk_fixed_put(GTK_FIXED(priv->fixed),GTK_WIDGET(button), pbutton->x, pbutton->y);
|
|
|
250 }
|
|
|
251
|
|
|
252 static void audacious_pbutton_size_allocate(GtkWidget *widget, GtkAllocation *allocation) {
|
|
|
253 AudaciousPButton *button = AUDACIOUS_PBUTTON (widget);
|
|
|
254 GtkAllocation child_alloc;
|
|
|
255
|
|
|
256 widget->allocation = *allocation;
|
|
|
257 if (GTK_BIN (button)->child) { //image should fill whole widget
|
|
|
258 child_alloc.x = widget->allocation.x;
|
|
|
259 child_alloc.y = widget->allocation.y;
|
|
|
260 child_alloc.width = MAX (1, widget->allocation.width);
|
|
|
261 child_alloc.height = MAX (1, widget->allocation.height);
|
|
|
262
|
|
|
263 gtk_widget_size_allocate (GTK_BIN (button)->child, &child_alloc);
|
|
|
264 }
|
|
|
265 }
|
|
|
266
|
|
|
267 static void button_pressed(AudaciousPButton *button) {
|
|
|
268 button->button_down = TRUE;
|
|
|
269 audacious_pbutton_update_state(button);
|
|
|
270 }
|
|
|
271
|
|
|
272 static void button_released(AudaciousPButton *button) {
|
|
|
273 button->button_down = FALSE;
|
|
|
274 if(button->hover) audacious_pbutton_clicked(button);
|
|
|
275 audacious_pbutton_update_state(button);
|
|
|
276 }
|
|
|
277
|
|
|
278 static void audacious_pbutton_update_state(AudaciousPButton *button) {
|
|
|
279 _audacious_pbutton_set_pressed(button, button->button_down);
|
|
|
280 }
|
|
|
281
|
|
|
282 void _audacious_pbutton_set_pressed (AudaciousPButton *button, gboolean pressed) {
|
|
|
283 if (pressed != button->pressed) {
|
|
|
284 button->pressed = pressed;
|
|
|
285 audacious_pbutton_paint(button);
|
|
|
286 }
|
|
|
287 }
|
|
|
288
|
|
|
289 static gboolean audacious_pbutton_button_press(GtkWidget *widget, GdkEventButton *event) {
|
|
|
290 AudaciousPButton *button;
|
|
|
291
|
|
|
292 if (event->type == GDK_BUTTON_PRESS) {
|
|
|
293 button = AUDACIOUS_PBUTTON(widget);
|
|
|
294
|
|
|
295 if (event->button == 1)
|
|
|
296 audacious_pbutton_pressed (button);
|
|
|
297 }
|
|
|
298
|
|
|
299 return TRUE;
|
|
|
300 }
|
|
|
301
|
|
|
302 static gboolean audacious_pbutton_button_release(GtkWidget *widget, GdkEventButton *event) {
|
|
|
303 AudaciousPButton *button;
|
|
|
304 if (event->button == 1) {
|
|
|
305 button = AUDACIOUS_PBUTTON(widget);
|
|
|
306 audacious_pbutton_released(button);
|
|
|
307 }
|
|
|
308
|
|
|
309 return TRUE;
|
|
|
310 }
|
|
|
311
|
|
|
312 void audacious_pbutton_pressed(AudaciousPButton *button) {
|
|
|
313 g_return_if_fail(AUDACIOUS_IS_PBUTTON(button));
|
|
|
314 g_signal_emit(button, button_signals[PRESSED], 0);
|
|
|
315 }
|
|
|
316
|
|
|
317 void audacious_pbutton_released(AudaciousPButton *button) {
|
|
|
318 g_return_if_fail(AUDACIOUS_IS_PBUTTON(button));
|
|
|
319 g_signal_emit(button, button_signals[RELEASED], 0);
|
|
|
320 }
|
|
|
321
|
|
|
322 void audacious_pbutton_clicked(AudaciousPButton *button) {
|
|
|
323 g_return_if_fail(AUDACIOUS_IS_PBUTTON(button));
|
|
|
324 g_signal_emit(button, button_signals[CLICKED], 0);
|
|
|
325 }
|
|
|
326
|
|
|
327 static gboolean audacious_pbutton_enter_notify(GtkWidget *widget, GdkEventCrossing *event) {
|
|
|
328 AudaciousPButton *button;
|
|
|
329
|
|
|
330 button = AUDACIOUS_PBUTTON(widget);
|
|
|
331 button->hover = TRUE;
|
|
|
332 if(button->button_down) _audacious_pbutton_set_pressed(button, TRUE);
|
|
|
333
|
|
|
334 return FALSE;
|
|
|
335 }
|
|
|
336
|
|
|
337 static gboolean audacious_pbutton_leave_notify(GtkWidget *widget, GdkEventCrossing *event) {
|
|
|
338 AudaciousPButton *button;
|
|
|
339
|
|
|
340 button = AUDACIOUS_PBUTTON (widget);
|
|
|
341 button->hover = FALSE;
|
|
|
342 if(button->button_down) _audacious_pbutton_set_pressed(button, FALSE);
|
|
|
343
|
|
|
344 return FALSE;
|
|
|
345 }
|
|
|
346
|
|
|
347 static void audacious_pbutton_add(GtkContainer *container, GtkWidget *widget) {
|
|
|
348 GTK_CONTAINER_CLASS (parent_class)->add(container, widget);
|
|
|
349 }
|
|
|
350
|
|
|
351 static void audacious_pbutton_set_doublesize(AudaciousPButton *button) {
|
|
|
352 //FIXME!
|
|
|
353 printf("Double size not implemented yet!\n");
|
|
|
354 }
|
|
|
355
|
|
|
356 static void audacious_pbutton_paint(AudaciousPButton *button) {
|
|
|
357 GtkWidget *widget = GTK_WIDGET (button);
|
|
|
358 AudaciousPButtonPrivate *priv = AUDACIOUS_PBUTTON_GET_PRIVATE (button);
|
|
|
359
|
|
|
360 GdkPixmap *obj;
|
|
|
361 obj = gdk_pixmap_new(NULL, priv->w, priv->h, gdk_rgb_get_visual()->depth);
|
|
|
362 skin_draw_pixmap(bmp_active_skin, obj, priv->gc, priv->skin_index2,
|
|
|
363 button->pressed ? button->px : button->nx,
|
|
|
364 button->pressed ? button->py : button->ny,
|
|
|
365 0, 0, priv->w, priv->h);
|
|
|
366 gtk_image_set_from_pixmap(GTK_IMAGE(priv->image), obj, NULL);
|
|
|
367 gtk_widget_queue_resize(widget);
|
|
|
368 }
|