[DataView] Fix bold of playing song, italic 'prioritized songs'
[gmpc.git] / src / gmpc-mpddata-treeview.gob
blob322254ee6c28f433455ca0d71a042a3bde1a0132
1 /* Gnome Music Player Client (GMPC)
2  * Copyright (C) 2004-2012 Qball Cow <qball@gmpclient.org>
3  * Project homepage: http://gmpclient.org/
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.
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.
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 requires 2.0.0
22 %ht{
23 #include <gtk/gtk.h>
24 #include <gdk/gdkkeysyms.h>
26 %privateheader{
27 #include "main.h"
28 #include "config.h"
29 #include <glib/gi18n.h>
30 #include "gmpc-mpddata-model.h"
31 #include "eggcolumnchooserdialog.h"
32 #include "gmpc-mpddata-model-playlist.h"
33 #include "gmpc-metaimage.h"
36 %h{
38 #define NUM_COLS 20
39 #define MOUSE_OFFSET 10
40 #define ENABLE_GRADIENT_LOOK 1
41 #define BACKGROUND_OPACITY 0.92
42 #define BOTTOM_GRADIENT_HEIGHT 30
45 enum {
46         DND_SONG
48 extern GtkTargetEntry gmt_targetentries[];
53 GtkTargetEntry gmt_targetentries[] =
55         { (gchar *)"GTK_TREE_MODEL_ROW",                                        GTK_TARGET_SAME_APP             , DND_SONG}
57 static int col_ids[NUM_COLS] = {
58     MPDDATA_MODEL_COL_MARKUP,
59     MPDDATA_MODEL_COL_SONG_ARTIST,                            /* album name */
60     MPDDATA_MODEL_COL_SONG_ALBUM,                             /* album name */
61     MPDDATA_MODEL_COL_SONG_TITLE,                             /* song title */
62     MPDDATA_MODEL_COL_SONG_TITLEFILE,               /* song title */
63     MPDDATA_MODEL_COL_SONG_GENRE,                             /* song genre */
64     MPDDATA_MODEL_COL_SONG_TRACK,                             /* song track */
65     MPDDATA_MODEL_COL_SONG_NAME,                              /* stream name */
66     MPDDATA_MODEL_COL_SONG_COMPOSER,                /* composer name */
67     MPDDATA_MODEL_COL_SONG_PERFORMER,               /* performer */
68     MPDDATA_MODEL_COL_SONG_DATE,                              /* date */
69     MPDDATA_MODEL_COL_SONG_LENGTH_FORMAT,         /* length formatted */
70     MPDDATA_MODEL_COL_SONG_DISC,                              /* disc */
71     MPDDATA_MODEL_COL_SONG_COMMENT,                         /* comment */
72     MPDDATA_MODEL_COL_ICON_ID,                                /* icon id */
73     MPDDATA_MODEL_COL_SONG_POS,
74     MPDDATA_MODEL_COL_SONG_ALBUMARTIST,
75                 MPDDATA_MODEL_COL_PATH_EXTENSION,                               /* Extension */
76                 MPDDATA_MODEL_COL_PATH_DIRECTORY,                               /* Directory */
77     MPDDATA_MODEL_COL_SONG_PRIORITY,
79 static const gchar *col_names[NUM_COLS] = {
80     N_("Markup"),
81     N_("Artist"),
82     N_("Album"),
83     N_("Title"),
84     N_("File"),
85     N_("Genre"),
86     N_("Track"),
87     N_("Name"),
88     N_("Composer"),
89     N_("Performer"),
90     N_("Date"),
91     N_("Duration"),
92     N_("Disc"),
93     N_("Comment"),
94     N_("Icon Id"),
95     N_("Position"),
96     N_("AlbumArtist"),
97     N_("Extension"),
98     N_("Directory"),
99     N_("Priority")
102 static gint  col_enabled[NUM_COLS] = {
103     FALSE,//"Markup",
104     TRUE, //"Artist",
105     TRUE,//"Album",
106     TRUE,//"Title",
107     FALSE,//"File",
108     FALSE,//"Genre",
109     FALSE,//"Track",
110     FALSE,//"Name",
111     FALSE,//"Composer",
112     FALSE,//"Performer",
113     FALSE,//"Date",
114     FALSE,//"Duration",
115     FALSE,//"Disc",
116     FALSE,//"Comment",
117     TRUE,//"Icon Id"
118     FALSE,//"Position"
119     FALSE,//"AlbumArtist"
120     FALSE,//Extension
121     FALSE,//Directory
122     FALSE//Priority
125 static gint  col_position[NUM_COLS] = {
126     14,//"Markup",
127     3, //"Artist",
128     2,//"Album",
129     1,//"Title",
130     4,//"File",
131     5,//"Genre",
132     6,//"Track",
133     7,//"Name",
134     8,//"Composer",
135     9,//"Performer",
136     10,//"Date",
137     11,//"Duration",
138     12,//"Disc",
139     13,//"Comment",
140     0,//"Icon Id"
141     15, // "Position"
142     18, // "AlbumArtist"
143     16,// Extension
144     17, // Directory
145     19
148 static GList *paste_queue = NULL;
149 #define LOG_DOMAIN "MpdData.TreeView"
152 class Gmpc:MpdData:Treeview from Gtk:Tree:View {
153         private gchar *name = {NULL} destroywith g_free;
154         private gboolean do_sort = {TRUE};
155         private GtkTreeViewColumn *columns[NUM_COLS];
156         /* Tooltip */
157         private GtkWidget   *tooltip_window = {NULL};
158         private GtkWidget   *tw_image = {NULL};
159         private GtkWidget   *tw_title = {NULL};
160         private GtkWidget   *tw_artist = {NULL};
161         private GtkWidget   *tw_album = {NULL};
162         private GtkWidget   *tw_genre = {NULL};
163         private GtkWidget   *tw_date = {NULL};
164         private GtkWidget   *tw_length = {NULL};
165         private gchar       *file = NULL;
167         private gboolean    pressed = FALSE;
174         public
175                 GtkWidget * new (const char *name (check null), gboolean sort, Gtk:Tree:Model *model (check type null))
176                 {
177                         Self *self = GET_NEW;
178                         self->_priv->name = g_strdup(name);
179                         self->_priv->do_sort = sort;
181                         gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(self), TRUE);
182                         gtk_tree_view_set_model(GTK_TREE_VIEW(self), model);
183                         /* init the tree */
184                         self_do_init(self);
185                         /* set tooltip */
186                         self_enable_tooltip(self);
187                         g_signal_connect(G_OBJECT(self), "key-release-event", G_CALLBACK(self_paste_key_release_event), NULL);
191                         gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(self), GDK_BUTTON1_MASK, gmt_targetentries, 1, GDK_ACTION_COPY);
192                         return (GtkWidget *)self;
193                 }
194         private
195                 void do_init (self)
196                 {
197                         int i=0;
198                         gchar *conf_size,*conf_opt = g_strdup_printf("%s-colpos", self->_priv->name);
199                         GtkTreeViewColumn *col = NULL;
200                         for(i = 0;i< NUM_COLS;i++)
201                         {
202                                 int conf_pos = cfg_get_single_value_as_int_with_default(config, conf_opt,col_names[i], col_position[i]);
203                                 col = self_add_column(self,col_names[i],col_ids[i],conf_pos);
204                                 g_object_set_data(G_OBJECT(col), "id",GINT_TO_POINTER(i));
205                         }
206                         q_free(conf_opt);
207                         conf_opt = g_strdup_printf("%s-colshow", self->_priv->name);
208                         conf_size = g_strdup_printf("%s-colsize", self->_priv->name);
209                         for(i = 0;i< NUM_COLS;i++)
210                         {
211                                 int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(self->_priv->columns[i]), "id"));
212                                 int col_size= cfg_get_single_value_as_int_with_default(config, conf_size,col_names[id], 200);
213                                 int col_show= cfg_get_single_value_as_int_with_default(config, conf_opt,col_names[id], col_enabled[id]);
214                                 gtk_tree_view_column_set_visible(self->_priv->columns[i],col_show);
215                                 gtk_tree_view_append_column(GTK_TREE_VIEW(self), self->_priv->columns[i]);
216                                 /* don't set the icon column */
217                                 if(col_ids[id]!= MPDDATA_MODEL_COL_ICON_ID)
218                                         gtk_tree_view_column_set_fixed_width(self->_priv->columns[i], col_size);
220                                 g_signal_connect_swapped(G_OBJECT(self->_priv->columns[i]), "notify::width", G_CALLBACK(self_column_width), self);
221                         }
222                         /* set the last column small, to stop weird grows */
223                         //for(i=NUM_COLS-1; i>=0 && !gtk_tree_view_column_get_visible(self->_priv->columns[i]);i--);
224                         //gtk_tree_view_column_set_fixed_width(self->_priv->columns[i], 150);
226                         q_free(conf_opt);
227                         q_free(conf_size);
229                         /* */
230                         gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(self)), GTK_SELECTION_MULTIPLE);
231                         gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW(self), TRUE);
232                         gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(self), TRUE);
234                         if(self->_priv->do_sort)
235                         {
236                                 int sort_col = cfg_get_single_value_as_int_with_default(config, self->_priv->name, "sort-column",MPDDATA_MODEL_COL_SONG_TITLE);
237                                 int sort_order = cfg_get_single_value_as_int_with_default(config, self->_priv->name, "sort-order", GTK_SORT_ASCENDING);
238                                 if(((sort_col < MPDDATA_MODEL_N_COLUMNS && sort_col >= 0) || sort_col == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID )&& (sort_order == GTK_SORT_ASCENDING || sort_order == GTK_SORT_DESCENDING)) {
239                                         gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(gtk_tree_view_get_model(GTK_TREE_VIEW(self))),sort_col, sort_order);
240                                 }
241                         }
242                 }
244         /**
245          * Save Column Setup
246          */
247         private
248                 void
249                 save_column_setup (self)
250                 {
251                         int i=0;
252                         GList *iter,*cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(self));
253                         gchar *conf_pos = NULL;
254                         gchar *conf_show = NULL;
256                         i = g_list_length(cols);
258                         if(i != NUM_COLS)
259                         {
260                                 g_list_free(cols);
261                                 return;
262                         }
263                         conf_pos = g_strdup_printf("%s-colpos", self->_priv->name);
264                         conf_show = g_strdup_printf("%s-colshow", self->_priv->name);
265                         //            conf_size = g_strdup_printf("%s-colsize", self->_priv->name);
266                         i=0;
267                         for(iter = cols; iter; iter = g_list_next(iter))
268                         {
269                                 GtkTreeViewColumn *column = iter->data;
270                                 int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "id"));
271                                 cfg_set_single_value_as_int(config, conf_pos, col_names[id], i);
272                                 cfg_set_single_value_as_int(config, conf_show, col_names[id], gtk_tree_view_column_get_visible(column));
273                                 /* only save width on > 0 columns */
274                                 //if(gtk_tree_view_column_get_width(column) > 0)
275                                 //    cfg_set_single_value_as_int(config, conf_size, col_names[id], gtk_tree_view_column_get_width(column));
276                                 i++;
277                         }
278                         q_free(conf_pos);
279                         q_free(conf_show);
280                         //          q_free(conf_size);
281                         g_list_free(cols);
283                         if(self->_priv->do_sort)
284                         {
285                                 int sort_col;
286                                 GtkSortType sort_order;
287                                 gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(gtk_tree_view_get_model(GTK_TREE_VIEW(self))), &sort_col, &sort_order);
288                                 cfg_set_single_value_as_int(config, self->_priv->name, "sort-column",sort_col);
289                                 cfg_set_single_value_as_int(config, self->_priv->name, "sort-order", sort_order);
290                         }
291                 }
293         override (G:Object)
294                 void
295                 dispose (G:Object *obj)
296                 {
297                         Self *self = GMPC_MPDDATA_TREEVIEW(obj);
298                         self_save_column_setup(self);
299                         PARENT_HANDLER(obj);
300                 }
301         private
302                 void
303                 highlight_row (GtkTreeViewColumn *tree_column,
304                                 GtkCellRenderer *cell,
305                                 GtkTreeModel *tree_model,
306                                 GtkTreeIter *iter,
307                                 gpointer data)
308                 {
310                         if(GMPC_IS_MPDDATA_MODEL_PLAYLIST(tree_model) && gmpc_mpddata_model_playlist_is_current_song(tree_model, iter))
311                                 g_object_set(G_OBJECT(cell), "weight", 800,NULL);
312                         else
313                                 g_object_set(G_OBJECT(cell), "weight", 400,NULL);
315                 }
316         private
317                 void
318                 column_width(self, GParamSpec *argc, GtkTreeViewColumn *column)
319                 {
320                         if(self->_priv->pressed)
321                         {
322                                 int width = gtk_tree_view_column_get_width(column);
323                                 int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "id"));
324                                 gchar *conf_size = g_strdup_printf("%s-colsize", self->_priv->name);
325                                 int w = cfg_get_single_value_as_int(config, conf_size, col_names[id]);
326                                 if(w != width)
327                                 {
328                                         cfg_set_single_value_as_int(config, conf_size, col_names[id],width);
329                                 }
330                                 q_free(conf_size);
331                         }
332                 }
334         private
335                 GtkTreeViewColumn *
336                 add_column(self, const char *columnname, int valuerow, int position)
337                 {
338                         GtkCellRenderer *renderer;
339                         GtkTreeViewColumn *column = NULL;
340                         GValue value = {0,};
342                         if(valuerow == MPDDATA_MODEL_COL_ICON_ID)
343                         {
344                                 renderer = gtk_cell_renderer_pixbuf_new();
345                                 g_value_init(&value, G_TYPE_FLOAT);
346                                 g_value_set_float(&value, 0.0);
347                                 g_object_set_property(G_OBJECT(renderer), "xalign", &value);
349                                 column = gtk_tree_view_column_new ();
350                                 gtk_tree_view_column_pack_start (column, renderer, TRUE);
351                                 gtk_tree_view_column_set_attributes (column,renderer,"icon-name", MPDDATA_MODEL_COL_ICON_ID,NULL);
353                                 gtk_tree_view_column_set_resizable(column, FALSE);
354                                 gtk_tree_view_column_set_fixed_width(column, 20);
355                         }
356                         else{
357                                 renderer = gtk_cell_renderer_text_new();
358                                 column = gtk_tree_view_column_new_with_attributes (_(columnname), renderer,
359                                                 "text", valuerow,NULL);
360                                 g_value_init(&value, G_TYPE_INT);
361                                 g_value_set_int(&value, PANGO_ELLIPSIZE_END);
362                                 g_object_set_property(G_OBJECT(renderer), "ellipsize", &value);
363                                 gtk_tree_view_column_set_resizable(column, TRUE);
364                                 if(GMPC_IS_MPDDATA_MODEL_PLAYLIST(gtk_tree_view_get_model(GTK_TREE_VIEW(self))))
365                                 {
366                                         g_object_set(G_OBJECT(renderer), "weight-set", TRUE, NULL);
367                                         gtk_tree_view_column_set_cell_data_func (column,renderer,self_highlight_row, NULL, NULL);
368                                 }
370                         }
371                         gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_FIXED);
372                         gtk_tree_view_column_set_reorderable(column, TRUE);
374                         self->_priv->columns[position] = column;
376                         if(self->_priv->do_sort)
377                         {
378                                 gtk_tree_view_column_set_sort_column_id(column,valuerow);
379                                 gtk_tree_view_column_set_sort_indicator(column, TRUE);
380                         }
382                         return column;
383                 }
384         /**
385          * Opens a column editor
386          */
387         public
388                 void
389                 edit_columns(self)
390                 {
391                         GtkWidget *dialog = egg_column_chooser_dialog_new(GTK_TREE_VIEW(self));
392                         gtk_widget_show_all(dialog);
393                         gtk_dialog_run(GTK_DIALOG(dialog));
394                         self_save_column_setup(self);
395                 }
397         override (G:Object)
398                 void
399                 finalize(G:Object *obj)
400                 {
401                         Self *self = SELF(obj);
402                         GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(obj));
403                         if(model)
404                         {
405                                 gtk_tree_view_set_model(GTK_TREE_VIEW(obj),NULL);
406                                 g_object_unref(model);
407                         }
408                         if(self->_priv->tooltip_window)
409                         {
410                                 gtk_widget_destroy(self->_priv->tooltip_window);
411                                 self->_priv->tooltip_window = NULL;
412                         }
413                         if(self->_priv->file)
414                         {
415                                 g_free(self->_priv->file);
416                                 self->_priv->file = NULL;
417                         }
418                         PARENT_HANDLER(obj);
419                 }
421         /****
422          * TREEVIEW POPUP
423          */
424         private gboolean query_tooltip(self,
425                         gint x, gint y,
426                         gboolean keyboard_tip,
427                         GtkTooltip *tooltip,
428                         gpointer data)
429         {
430                 GtkTreeView *treeview = GTK_TREE_VIEW(self);
431                 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
432                 GtkTreeIter iter;
433                 GtkTreePath *path = NULL;
434                 mpd_Song *song = NULL;
435                 int show = FALSE;
437                 if(!cfg_get_single_value_as_int_with_default(config, "GmpcTreeView", "show-tooltip", TRUE))
438                         return FALSE;
439                 if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW(treeview), &x, &y,
440                                         keyboard_tip,
441                                         &model, &path, &iter))
442                         return FALSE;
445                 gtk_tree_model_get(model, &iter,MPDDATA_MODEL_COL_MPDSONG, &song, -1);
446                 if(song)
447                 {
448                         show = TRUE;
449                         /* makes it look a bit nicer */
450                         if(self->_priv->file && song->file && strcmp(self->_priv->file, song->file))
451                         {
452                                 show = FALSE;
453                                 g_free(self->_priv->file);self->_priv->file = NULL;
454                         }
455                         else if(!(self->_priv->file && song->file && strcmp(self->_priv->file, song->file) == 0))
456                         {
457                                 gchar *temp;
459                                 gmpc_metaimage_update_cover_from_song(GMPC_METAIMAGE(self->_priv->tw_image), song);
460                                 if(self->_priv->file)
461                                         g_free(self->_priv->file);
462                                 self->_priv->file = NULL;
463                                 if(song->file)
464                                         self->_priv->file = g_strdup(song->file);
466                                 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_TITLE, &temp, -1);
467                                 gtk_label_set_text(GTK_LABEL(self->_priv->tw_title), temp);
468                                 g_free(temp);
470                                 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_ARTIST,&temp, -1);
471                                 gtk_label_set_text(GTK_LABEL(self->_priv->tw_artist), temp);
472                                 g_free(temp);
474                                 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_ALBUM, &temp, -1);
475                                 gtk_label_set_text(GTK_LABEL(self->_priv->tw_album), temp);
476                                 g_free(temp);
478                                 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_GENRE, &temp, -1);
479                                 gtk_label_set_text(GTK_LABEL(self->_priv->tw_genre), temp);
480                                 g_free(temp);
482                                 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_DATE, &temp, -1);
483                                 gtk_label_set_text(GTK_LABEL(self->_priv->tw_date), temp);
484                                 g_free(temp);
486                                 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_LENGTH_FORMAT, &temp, -1);
487                                 gtk_label_set_text(GTK_LABEL(self->_priv->tw_length), temp);
488                                 g_free(temp);
492                         }
493                 }
494                 gtk_tree_path_free(path);
495                 return show;
496         }
499         private
500                 gboolean
501                 tooltip_draw (GtkWidget *widget, cairo_t *context,gpointer data)
502                 {
503                         int stripe_x = 1;
504                         int stripe_y = 1;
505             GtkAllocation allocation;
506                         GdkColor color;
507                         GtkStyle *style = gtk_widget_get_style(widget);
508                         GdkColor *background_color = &style->base[GTK_STATE_NORMAL];
509                         cairo_surface_t *surface;
510                         cairo_t *cr;
511                         GdkScreen *screen = gtk_window_get_screen(GTK_WINDOW(widget));
512             gtk_widget_get_allocation(widget, &allocation);
513                         int stripe_height = allocation.height;// 128+8;
514 #ifdef ENABLE_GRADIENT_LOOK
515                         cairo_pattern_t *gradient;
516                         double r, g, b;
517                         int gradient_y = allocation.height - BOTTOM_GRADIENT_HEIGHT;
518 #endif
522                         cairo_set_operator(context, CAIRO_OPERATOR_SOURCE);
523                         surface = cairo_surface_create_similar(cairo_get_target(context),
524                                         CAIRO_CONTENT_COLOR_ALPHA,
525                                         allocation.width,
526                                         allocation.height);
527                         cr = cairo_create(surface);
532                         if (gdk_screen_is_composited(screen))
533                         {
534                                 cairo_set_source_rgba(cr,
535                                                 background_color->red   / 65535.0,
536                                                 background_color->green / 65535.0,
537                                                 background_color->blue  / 65535.0,
538                                                 BACKGROUND_OPACITY);
539                         }
540                         else
541                         {
542                                 gdk_cairo_set_source_color(cr, background_color);
543                         }
545                         cairo_rectangle(cr, 0, 0,
546                                         allocation.width,
547                                         allocation.height);
548                         cairo_fill(cr);
550 #ifdef ENABLE_GRADIENT_LOOK
551                         /* Add a very subtle gradient to the bottom of the notification */
552                         gradient = cairo_pattern_create_linear(0, gradient_y, 0,
553                                         allocation.height);
554                         cairo_pattern_add_color_stop_rgba(gradient, 0, 0, 0, 0, 0);
555                         cairo_pattern_add_color_stop_rgba(gradient, 1, 0, 0, 0, 0.15);
556                         cairo_rectangle(cr, 0, gradient_y, allocation.width,
557                                         BOTTOM_GRADIENT_HEIGHT);
558                         cairo_set_source(cr, gradient);
559                         cairo_fill(cr);
560                         cairo_pattern_destroy(gradient);
561 #endif
563                         cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
564                         cairo_set_line_width(cr, 1.0);
565                         cairo_rectangle(cr, 0.5, 0.5,allocation.width - 0.5, allocation.height - 0.5);
566                         cairo_stroke(cr);
569                         color = style->bg[GTK_STATE_SELECTED];
571                         cairo_rectangle(cr, stripe_x, stripe_y, 160, stripe_height);
573 #ifdef ENABLE_GRADIENT_LOOK
574                         r = color.red   / 65535.0;
575                         g = color.green / 65535.0;
576                         b = color.blue  / 65535.0;
578                         gradient = cairo_pattern_create_linear(stripe_x, 0, 160, 0);
579                         cairo_pattern_add_color_stop_rgba(gradient, 0, r, g, b, 1);
580                         cairo_pattern_add_color_stop_rgba(gradient, 1, r, g, b, 0);
581                         cairo_set_source(cr, gradient);
582                         cairo_fill(cr);
583                         cairo_pattern_destroy(gradient);
584 #else
585                         gdk_cairo_set_source_color(cr, &color);
586                         cairo_fill(cr);
587 #endif
589                         cairo_destroy(cr);
590                         cairo_set_source_surface(context, surface, 0, 0);
591                         cairo_paint(context);
592                         cairo_surface_destroy(surface);
594                         return FALSE;//GTK_WIDGET_CLASS(parent_class)->expose_event(widget, event);
595                 }
597         private void enable_tooltip(self)
598         {
599                 gchar *markup = NULL;
600                 GdkScreen *screen;
601 //              GdkColormap *colormap;
602                 GtkWidget *treeview = GTK_WIDGET(self);
603                 GtkWidget *table = gtk_table_new(6,2, FALSE);
604                 GtkWidget *vbox = gtk_hbox_new(FALSE, 0);
605                 GtkWidget *label,*ali;
606                 GtkSizeGroup *group  = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
607                 self->_priv->tooltip_window = gtk_window_new(GTK_WINDOW_POPUP);
608                 screen = gtk_window_get_screen(GTK_WINDOW(self->_priv->tooltip_window));
610                 //colormap = gdk_screen_get_rgba_colormap(screen);
612                 if (colormap != NULL && gdk_screen_is_composited(screen))
613                 {
614                         gtk_widget_set_colormap(self->_priv->tooltip_window, colormap);
615                 }
618                 gtk_widget_set_size_request(GTK_WIDGET(self->_priv->tooltip_window), 3*128,-1);
620                 gtk_widget_set_app_paintable(self->_priv->tooltip_window, TRUE);
621                 g_signal_connect(G_OBJECT(self->_priv->tooltip_window), "draw", G_CALLBACK(self_tooltip_draw), self);
623                 gtk_container_add(GTK_CONTAINER(self->_priv->tooltip_window), vbox);
624                 self->_priv->tw_image = gmpc_metaimage_new(META_ALBUM_ART);
626                 ali = gtk_alignment_new(0.0f, 0.0f, 0.0f, 0.0f);
627                 gtk_alignment_set_padding(GTK_ALIGNMENT(ali), 4,4,4,4);
628                 gtk_container_add(GTK_CONTAINER(ali), self->_priv->tw_image);
629                 gmpc_metaimage_set_size(GMPC_METAIMAGE(self->_priv->tw_image), 128);
631                 gtk_box_pack_start(GTK_BOX(vbox), ali, FALSE, FALSE, 0);
633                 gtk_table_set_row_spacings(GTK_TABLE(table), 6);
634                 gtk_table_set_col_spacings(GTK_TABLE(table), 6);
635                 /* set layout up */
636                 gtk_container_set_border_width(GTK_CONTAINER(vbox),1);
637                 gtk_container_set_border_width(GTK_CONTAINER(table), 6);
639                 label = gtk_label_new("");
640                 gtk_size_group_add_widget(group, label);
641                 markup = g_markup_printf_escaped("<b>%s:</b>", _("Title"));
642                 gtk_label_set_markup(GTK_LABEL(label), markup);
643                 g_free(markup);
644                 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
645                 gtk_table_attach(GTK_TABLE(table), label, 0,1,0,1,GTK_FILL, GTK_FILL,0,0);
646                 self->_priv->tw_title = gtk_label_new("n/a");
647                 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_title), 0.0,0.5);
648                 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_title), PANGO_ELLIPSIZE_END);
649                 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_title, 1,2,0,1,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
652                 label = gtk_label_new("");
653                 gtk_size_group_add_widget(group, label);
654                 markup = g_markup_printf_escaped("<b>%s:</b>", _("Artist"));
655                 gtk_label_set_markup(GTK_LABEL(label),markup);
656                 g_free(markup);
657                 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
658                 gtk_table_attach(GTK_TABLE(table), label, 0,1,1,2,GTK_FILL, GTK_FILL,0,0);
659                 self->_priv->tw_artist = gtk_label_new("n/a");
660                 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_artist), 0.0,0.5);
661                 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_artist),PANGO_ELLIPSIZE_END);
662                 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_artist, 1,2,1,2,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
666                 label = gtk_label_new("");
667                 gtk_size_group_add_widget(group, label);
668                 markup = g_markup_printf_escaped("<b>%s:</b>", _("Album"));
669                 gtk_label_set_markup(GTK_LABEL(label),markup);
670                 g_free(markup);
671                 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
672                 gtk_table_attach(GTK_TABLE(table), label, 0,1,2,3,GTK_FILL, GTK_FILL,0,0);
673                 self->_priv->tw_album = gtk_label_new("n/a");
674                 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_album), 0.0,0.5);
675                 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_album),PANGO_ELLIPSIZE_END);
676                 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_album, 1,2,2,3,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
678                 label = gtk_label_new("");
679                 gtk_size_group_add_widget(group, label);
680                 markup = g_markup_printf_escaped("<b>%s:</b>", _("Genre"));
681                 gtk_label_set_markup(GTK_LABEL(label), markup);
682                 g_free(markup);
683                 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
684                 gtk_table_attach(GTK_TABLE(table), label, 0,1,3,4,GTK_FILL, GTK_FILL,0,0);
685                 self->_priv->tw_genre = gtk_label_new("n/a");
686                 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_genre), 0.0,0.5);
687                 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_genre),PANGO_ELLIPSIZE_END);
688                 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_genre, 1,2,3,4,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
690                 label = gtk_label_new("");
691                 gtk_size_group_add_widget(group, label);
692                 markup = g_markup_printf_escaped("<b>%s:</b>", _("Date"));
693                 gtk_label_set_markup(GTK_LABEL(label), markup);
694                 g_free(markup);
695                 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
696                 gtk_table_attach(GTK_TABLE(table), label, 0,1,4,5,GTK_FILL, GTK_FILL,0,0);
697                 self->_priv->tw_date = gtk_label_new("n/a");
698                 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_date), 0.0,0.5);
699                 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_date),PANGO_ELLIPSIZE_END);
700                 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_date, 1,2,4,5,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
702                 label = gtk_label_new("");
703                 gtk_size_group_add_widget(group, label);
704                 markup = g_markup_printf_escaped("<b>%s:</b>", _("Duration"));
705                 gtk_label_set_markup(GTK_LABEL(label), markup);
706                 g_free(markup);
707                 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
708                 gtk_table_attach(GTK_TABLE(table), label, 0,1,5,6,GTK_FILL, GTK_FILL,0,0);
709                 self->_priv->tw_length = gtk_label_new("n/a");
710                 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_length), 0.0,0.5);
711                 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_length),PANGO_ELLIPSIZE_END);
712                 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_length, 1,2,5,6,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
717                 g_object_unref(group);
719                 gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0);
723                 g_signal_connect(G_OBJECT(treeview),
724                                 "query-tooltip",
725                                 G_CALLBACK(self_query_tooltip),
726                                 NULL);
727                 gtk_widget_set_tooltip_window(treeview, GTK_WINDOW(self->_priv->tooltip_window));
728                 gtk_widget_show_all(vbox);
729         }
735         /**
736          * Right mouse click behaviour fix
737          */
738         private
739                 gboolean click_fix (self, GdkEventButton *event)
740                 {
741                         GtkTreePath *path = NULL;
742                         self->_priv->pressed = TRUE;
743                         if(event->button == 3 && event->window != NULL && gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(self), event->x, event->y,&path,NULL,NULL,NULL))
744                         {
745                                 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(self));
746                                 if(gtk_tree_selection_path_is_selected(sel, path))
747                                 {
748                                         gtk_tree_path_free(path);
749                                         return TRUE;
751                                 }
752                         }
753                         if(path) {
754                                 gtk_tree_path_free(path);
755                         }
756                         return FALSE;
757                 }
759         private
760                 gboolean click_released (self, GdkEventButton *event)
761                 {
762                         self->_priv->pressed = FALSE;
763                         return FALSE;
764                 }
765         public
766                 void
767                 enable_click_fix(self)
768                 {
769                         g_signal_connect(G_OBJECT(self), "button-press-event", G_CALLBACK(self_click_fix), NULL);
771                         g_signal_connect(G_OBJECT(self), "button-release-event", G_CALLBACK(self_click_released), NULL);
772                 }
773         /**
774          * Copy paste stuff
775          */
776         signal last NONE (POINTER)
777                 void
778                 paste_before(self, GList *items)
779                 {
780                 }
782         signal last NONE (POINTER)
783                 void
784                 paste_after(self, const GList *items)
785                 {
786                 }
787         signal last NONE (NONE)
788                 void
789                 cut(self)
790                 {
791                 }
793         private void insert_selected_rows(self,gboolean replace)
794         {
795             GtkTreeModel *model = NULL;
796             GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self));
797             GList *iter, *list = gtk_tree_selection_get_selected_rows(selection, &model);
798             int added = 0;
799             for(iter = g_list_first(list); iter != NULL; iter = g_list_next(iter))
800             {
801                 gchar *name;
802                 gint type;
803                 GtkTreeIter titer;
804                 GtkTreePath *path = iter->data;
805                 gtk_tree_model_get_iter(model, &titer, path);
806                 gtk_tree_model_get(model, &titer, MPDDATA_MODEL_COL_PATH, &name, MPDDATA_MODEL_ROW_TYPE, &type, -1);
807                 if (type == MPD_DATA_TYPE_SONG || type == MPD_DATA_TYPE_DIRECTORY) {
808                     /* add them to the add list */
809                     mpd_playlist_queue_add(connection, name);
810                     added++;
811                 } else if (type == MPD_DATA_TYPE_PLAYLIST) {
812                     mpd_playlist_queue_load(connection, name);
813                     added++;
814                 }
815             }
816             if(replace && added > 0) {
817                 mpd_playlist_clear(connection);
818             }
819             mpd_playlist_queue_commit(connection);
820             if(replace && added > 0) {
821                 mpd_player_play(connection);
822             }
823             g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
824             g_list_free (list);
825         }
826         /**
827          * This will add selected songs. (only songs)
828          * with priority. If song has an song-id, it only changes priority.
829          */ 
830         public void insert_selected_rows_with_priority(self)
831         {
832             GtkTreeModel *model = NULL;
833             GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self));
834             GList *iter, *list = gtk_tree_selection_get_selected_rows(selection, &model);
835             int priority = 255;
836             int sel_rows = gtk_tree_selection_count_selected_rows(selection);
838             // Max count.
839             if(sel_rows >= 254) {
840                 playlist3_show_error_message(_("You can only queue 254 songs at the time."),
841                         ERROR_WARNING);
842                 return ;
843             }
844             for(iter = g_list_first(list); iter != NULL; iter = g_list_next(iter))
845             {
846                 int id;
847                 gchar *name = NULL;
848                 gint type;
849                 GtkTreeIter titer;
850                 GtkTreePath *path = iter->data;
851                 gtk_tree_model_get_iter(model, &titer, path);
852                 gtk_tree_model_get(model, &titer,
853                         MPDDATA_MODEL_COL_PATH, &name,
854                         MPDDATA_MODEL_COL_SONG_ID, &id,
855                         MPDDATA_MODEL_ROW_TYPE, &type, -1);
856                 if (type == MPD_DATA_TYPE_SONG ) {
857                     /* add them to the add list */
858                     if(id < 0){
859                         id = mpd_playlist_add_get_id(connection, name);
860                     }
861                     if(id >= 0) {
862                         mpd_playlist_set_priority(connection, id, priority--);
863                     }
864                 }
865                 g_free(name);
866             }
867             g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
868             g_list_free (list);
869         }
871         private
872                 int
873                 paste_key_release_event(self, GdkEventKey *event,gpointer data)
874                 {
875             if(event->keyval == GDK_KEY_q && (event->state&GDK_MOD1_MASK) > 0) {
876                 if(mpd_check_connected(connection) &&
877                         mpd_server_check_command_allowed(connection, "prioid") == 
878                         MPD_SERVER_COMMAND_ALLOWED) 
879                 {
880                     self_insert_selected_rows_with_priority(self);
881                     return TRUE;
882                 }
883             }
884             else if(event->keyval == GDK_KEY_Insert || event->keyval == GDK_KEY_KP_Insert) {
885                 if(mpd_check_connected(connection))
886                 {
887                     self_insert_selected_rows(self,((event->state & GDK_CONTROL_MASK) > 0));
888                     return TRUE;
889                 }
891             }
892             if(event->keyval == GDK_KEY_Menu) {
893                 GdkEventButton bevent;
894                 gboolean value = FALSE;
895                 bevent.window = NULL;
896                 bevent.button = 3;
897                 bevent.time = event->time;
898                 g_signal_emit_by_name(self, "button-press-event", &bevent, &value,NULL);
899                 if(!value){
900                     g_signal_emit_by_name(self, "button-release-event", &bevent, &value,NULL);
901                 }
903                 return TRUE;
904             }
905                         if (event->keyval == GDK_KEY_c && event->state&GDK_CONTROL_MASK)
906                         {
907                                 self_paste_copy_songs(self, NULL);
908                                 return TRUE;
909                         }
910                         if(paste_queue )
911                         {
912                                 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[PASTE_BEFORE_SIGNAL], 0, TRUE))
913                                 {
914                                         if (event->keyval == GDK_KEY_b && event->state&GDK_CONTROL_MASK)
915                                         {
916                                                 self_paste_paste_before_songs(self, NULL);
917                                                 return TRUE;
919                                         }
920                                 }
922                                 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[PASTE_AFTER_SIGNAL], 0, TRUE))
923                                 {
924                                         if (event->keyval == GDK_KEY_v && event->state&GDK_CONTROL_MASK)
925                                         {
926                                                 self_paste_paste_after_songs(self, NULL);
927                                                 return TRUE;
928                                         }
929                                 }
930                         }
932                         if (gtk_tree_selection_count_selected_rows (gtk_tree_view_get_selection(GTK_TREE_VIEW(self))) > 0)
933                         {
934                                 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[CUT_SIGNAL], 0, TRUE))
935                                 {
936                                         if (event->keyval == GDK_KEY_x && event->state&GDK_CONTROL_MASK)
937                                         {
938                                                 self_paste_cut_songs(self, NULL);
939                                                 return TRUE;
940                                         }
941                                 }
942                         }
943                         return FALSE;
944                 }
945         private
946                 void
947                 paste_cut_songs(self, GtkMenuItem *item)
948                 {
949                         self_paste_copy_songs(self, item);
950                         self_cut(self);
951                 }
952         private
953                 void
954                 paste_paste_after_songs(self, GtkMenuItem *menuitem)
955                 {
956                         self_paste_after(self, g_list_first(paste_queue));
957                         /* free old entries
958                            g_list_foreach(paste_queue, (GFunc)g_free, NULL);
959                            g_list_free(paste_queue);
960                            paste_queue = NULL;
961                          */
962                 }
964         private
965                 void
966                 paste_paste_before_songs(self, GtkMenuItem *menuitem)
967                 {
968                         self_paste_before(self, g_list_first(paste_queue));
969                         /* free old entries
970                            g_list_foreach(paste_queue, (GFunc)g_free, NULL);
971                            g_list_free(paste_queue);
972                            paste_queue = NULL;
973                          */
974                 }
976         private
977                 void
978                 paste_copy_songs(self, GtkMenuItem *menitem)
979                 {
980                         GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(self));
981                         /* free old entries */
982                         g_list_foreach(paste_queue, (GFunc)g_free, NULL);
983                         g_list_free(paste_queue);
984                         paste_queue = NULL;
985                         /* check if where connected */
986                         /* see if there is a row selected */
987                         if (gtk_tree_selection_count_selected_rows (selection) > 0)
988                         {
989                                 GList *list = NULL, *llist = NULL;
990                                 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(self));
991                                 /* start a command list */
992                                 /* grab the selected songs */
993                                 list = gtk_tree_selection_get_selected_rows (selection, &model);
994                                 /* grab the last song that is selected */
995                                 llist = g_list_last (list);
996                                 /* remove every selected song one by one */
997                                 do{
998                                         GtkTreeIter iter;
999                                         gtk_tree_model_get_iter (model, &iter,(GtkTreePath *) llist->data);
1000                                         /* Trick that avoids roundtrip to mpd */
1001                                         {
1002                                                 char *path = NULL;
1003                                                 int type = 0;
1004                                                 /* this one allready has the pos. */
1005                                                 gtk_tree_model_get (model, &iter,
1006                                                                 MPDDATA_MODEL_ROW_TYPE,&type,
1007                                                                 MPDDATA_MODEL_COL_PATH, &path,
1008                                                                 -1);
1009                                                 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Copying song, into queue: %s\n", path);
1010                                                 if(type == MPD_DATA_TYPE_SONG) {
1011                                                         paste_queue = g_list_prepend(paste_queue, path);
1012                                                 } else if (type == MPD_DATA_TYPE_DIRECTORY) {
1013                                                         MpdData *data = mpd_database_get_directory_recursive(connection, path);
1014                                                         for(;data; data= mpd_data_get_next(data)){
1015                                                                 if(data->type == MPD_DATA_TYPE_SONG) {
1016                                                                         paste_queue = g_list_prepend(paste_queue, g_strdup(data->song->file));
1017                                                                 }
1018                                                         }
1019                                                         g_free(path);
1020                                                 } else if (type == MPD_DATA_TYPE_PLAYLIST) {
1021                                                         MpdData *data = mpd_database_get_playlist_content(connection, path);
1022                                                         for(;data; data= mpd_data_get_next(data)){
1023                                                                 if(data->type == MPD_DATA_TYPE_SONG) {
1024                                                                         paste_queue = g_list_prepend(paste_queue, g_strdup(data->song->file));
1025                                                                 }
1026                                                         }
1027                                                         g_free(path);
1028                                                 }
1029                                         }
1030                                 } while ((llist = g_list_previous (llist)));
1031                                 /* free list */
1032                                 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
1033                                 g_list_free (list);
1034                         }
1035                         paste_queue = g_list_reverse(paste_queue);
1036                 }
1038         public
1039                 int
1040                 right_mouse_intergration(self, GtkMenu *menu)
1041                 {
1042                         int retv = 0;
1043                         int i;
1044                         GtkWidget *menu_item;
1045                         GtkTreeSelection *selection = NULL;
1046                         GtkWidget *submenu = gtk_menu_new();
1047                         for(i=0; i< num_plugins;i++)
1048                         {
1049                                 if(gmpc_plugin_get_enabled(plugins[i]))
1050                                 {
1051                                         retv += gmpc_plugin_browser_song_list_option_menu(plugins[i],self, GTK_MENU(submenu));
1052                                 }
1053                         }
1054                         /* If no submenu item was added, destroy the submenu */
1055                         if(!retv) gtk_widget_destroy(submenu);
1056                         else{
1057                                 GList *temp = gtk_container_get_children(GTK_CONTAINER(menu));
1058                                 if(temp){
1059                                         menu_item = gtk_separator_menu_item_new();
1060                                         g_list_free(temp);
1061                                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1062                                 }
1063                                 /* Add a tools menu item with the previously generated menu as submenu */
1064                                 menu_item = gtk_menu_item_new_with_label(_("Tools"));
1065                                 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu);
1066                                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1067                         }
1070                         /**
1071                          * Paste integration
1072                          */
1074                         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self));
1075                         if(selection && gtk_tree_selection_count_selected_rows(selection))
1076                         {
1077                                 GList *temp = gtk_container_get_children(GTK_CONTAINER(menu));
1078                                 if(temp){
1079                                         menu_item = gtk_separator_menu_item_new();
1080                                         g_list_free(temp);
1081                                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1082                                 }
1084                                 menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_COPY, NULL);
1085                                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1086                                 g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_paste_copy_songs), self);
1087                                 retv++;
1088                         }
1089                         if(paste_queue )
1090                         {
1091                                 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[PASTE_BEFORE_SIGNAL], 0, TRUE))
1092                                 {
1093                                         menu_item = gtk_image_menu_item_new_with_label(_("Paste before"));
1094                                         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
1095                                                         gtk_image_new_from_stock(GTK_STOCK_PASTE, GTK_ICON_SIZE_MENU));
1096                                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1097                                         g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_paste_paste_before_songs), self);
1098                                         retv++;
1099                                 }
1100                                 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[PASTE_AFTER_SIGNAL], 0, TRUE))
1101                                 {
1102                                         menu_item = gtk_image_menu_item_new_with_label(_("Paste after"));
1103                                         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
1104                                                         gtk_image_new_from_stock(GTK_STOCK_PASTE, GTK_ICON_SIZE_MENU));
1105                                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1106                                         g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_paste_paste_after_songs), self);
1107                                         retv++;
1108                                 }
1109                         }
1111                         if (gtk_tree_selection_count_selected_rows (gtk_tree_view_get_selection(GTK_TREE_VIEW(self))) > 0)
1112                         {
1113                                 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[CUT_SIGNAL], 0, TRUE))
1114                                 {
1115                                         menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CUT,NULL);
1116                                         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
1117                                                         gtk_image_new_from_stock(GTK_STOCK_PASTE, GTK_ICON_SIZE_MENU));
1118                                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1119                                         g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_paste_cut_songs), self);
1120                                         retv++;
1121                                 }
1122                         }
1124                         {
1125                                 GList *temp = gtk_container_get_children(GTK_CONTAINER(menu));
1126                                 if(temp){
1127                                         menu_item = gtk_separator_menu_item_new();
1128                                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1129                                         g_list_free(temp);
1130                                         retv++;
1131                                 }
1132                         }
1133                         /** Edit column */
1134                         menu_item = gtk_image_menu_item_new_with_label(_("Edit Columns"));
1135                         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), gtk_image_new_from_stock(GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU));
1136                         g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_edit_columns), self);
1137                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1138                         retv++;
1140                         return retv;
1141                 }
1143         public
1144                 void
1145                 cleanup(void)
1146                 {
1147                         if(paste_queue)
1148                         {
1149                                 g_list_foreach(paste_queue, (GFunc)g_free, NULL);
1150                                 g_list_free(paste_queue);
1151                         }
1152                         paste_queue = NULL;
1153                 }
1156 /* vim: set noexpandtab ts=4 sw=4 sts=4 tw=120: */