Update the go-menu when disabling browser in AE.
[gmpc.git] / src / gmpc-mpddata-treeview.gob
bloba0c46c99034e989fe925a547e445c65de41af8ee
1 /* Gnome Music Player Client (GMPC)
2  * Copyright (C) 2004-2011 Qball Cow <qball@sarine.nl>
3  * Project homepage: http://gmpc.wikia.com/
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.
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 19
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         { (const 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 */
78 static const gchar *col_names[NUM_COLS] = {
79     N_("Markup"),
80     N_("Artist"),
81     N_("Album"),
82     N_("Title"),
83     N_("File"),
84     N_("Genre"),
85     N_("Track"),
86     N_("Name"),
87     N_("Composer"),
88     N_("Performer"),
89     N_("Date"),
90     N_("Duration"),
91     N_("Disc"),
92     N_("Comment"),
93     N_("Icon Id"),
94     N_("Position"),
95     N_("AlbumArtist"),
96     N_("Extension"),
97     N_("Directory")
98 }; 
100 static gint  col_enabled[NUM_COLS] = {
101     FALSE,//"Markup",
102     TRUE, //"Artist",
103     TRUE,//"Album",
104     TRUE,//"Title",
105     FALSE,//"File",
106     FALSE,//"Genre",
107     FALSE,//"Track",
108     FALSE,//"Name",
109     FALSE,//"Composer",
110     FALSE,//"Performer",
111     FALSE,//"Date",
112     FALSE,//"Duration",
113     FALSE,//"Disc",
114     FALSE,//"Comment",
115     TRUE,//"Icon Id"
116     FALSE,//"Position"
117     FALSE,//"AlbumArtist"
118     FALSE,//Extension
119     FALSE//Directory
122 static gint  col_position[NUM_COLS] = {
123     14,//"Markup",
124     3, //"Artist",
125     2,//"Album",
126     1,//"Title",
127     4,//"File",
128     5,//"Genre",
129     6,//"Track",
130     7,//"Name",
131     8,//"Composer",
132     9,//"Performer",
133     10,//"Date",
134     11,//"Duration",
135     12,//"Disc",
136     13,//"Comment",
137     0,//"Icon Id"
138     15, // "Position"
139     18, // "AlbumArtist"
140     16,// Extension
141     17 // Directory
144 static GList *paste_queue = NULL;
145 #define LOG_DOMAIN "MpdData.TreeView"
148 class Gmpc:MpdData:Treeview from Gtk:Tree:View {
149         private gchar *name = {NULL} destroywith g_free;
150         private gboolean do_sort = {TRUE};
151         private GtkTreeViewColumn *columns[NUM_COLS];
152         /* Tooltip */
153         private GtkWidget   *tooltip_window = {NULL};
154         private GtkWidget   *tw_image = {NULL};
155         private GtkWidget   *tw_title = {NULL};
156         private GtkWidget   *tw_artist = {NULL};
157         private GtkWidget   *tw_album = {NULL};
158         private GtkWidget   *tw_genre = {NULL};
159         private GtkWidget   *tw_date = {NULL};
160         private GtkWidget   *tw_length = {NULL};
161         private gchar       *file = NULL;
163         private gboolean    pressed = FALSE;
170         public 
171                 GtkWidget * new (const char *name (check null), gboolean sort, Gtk:Tree:Model *model (check type null))
172                 {
173                         Self *self = GET_NEW;
174                         self->_priv->name = g_strdup(name);
175                         self->_priv->do_sort = sort;
177                         gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(self), TRUE);
178                         gtk_tree_view_set_model(GTK_TREE_VIEW(self), model);
179                         /* init the tree */
180                         self_do_init(self);
181                         /* set tooltip */
182                         self_enable_tooltip(self);
183                         g_signal_connect(G_OBJECT(self), "key-release-event", G_CALLBACK(self_paste_key_release_event), NULL);
187                         gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(self), GDK_BUTTON1_MASK, gmt_targetentries, 1, GDK_ACTION_COPY);
188                         return (GtkWidget *)self;
189                 }
190         private
191                 void do_init (self)
192                 {
193                         int i=0;
194                         gchar *conf_size,*conf_opt = g_strdup_printf("%s-colpos", self->_priv->name);
195                         GtkTreeViewColumn *col = NULL;
196                         for(i = 0;i< NUM_COLS;i++)
197                         { 
198                                 int conf_pos = cfg_get_single_value_as_int_with_default(config, conf_opt,col_names[i], col_position[i]); 
199                                 col = self_add_column(self,col_names[i],col_ids[i],conf_pos);
200                                 g_object_set_data(G_OBJECT(col), "id",GINT_TO_POINTER(i));      
201                         }
202                         q_free(conf_opt);
203                         conf_opt = g_strdup_printf("%s-colshow", self->_priv->name);
204                         conf_size = g_strdup_printf("%s-colsize", self->_priv->name);
205                         for(i = 0;i< NUM_COLS;i++)
206                         { 
207                                 int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(self->_priv->columns[i]), "id"));
208                                 int col_size= cfg_get_single_value_as_int_with_default(config, conf_size,col_names[id], 200); 
209                                 int col_show= cfg_get_single_value_as_int_with_default(config, conf_opt,col_names[id], col_enabled[id]); 
210                                 gtk_tree_view_column_set_visible(self->_priv->columns[i],col_show);
211                                 gtk_tree_view_append_column(GTK_TREE_VIEW(self), self->_priv->columns[i]);
212                                 /* don't set the icon column */
213                                 if(col_ids[id]!= MPDDATA_MODEL_COL_ICON_ID)
214                                         gtk_tree_view_column_set_fixed_width(self->_priv->columns[i], col_size);
216                                 g_signal_connect_swapped(G_OBJECT(self->_priv->columns[i]), "notify::width", G_CALLBACK(self_column_width), self);
217                         }
218                         /* set the last column small, to stop weird grows */
219                         //for(i=NUM_COLS-1; i>=0 && !gtk_tree_view_column_get_visible(self->_priv->columns[i]);i--);
220                         //gtk_tree_view_column_set_fixed_width(self->_priv->columns[i], 150);
222                         q_free(conf_opt);
223                         q_free(conf_size);
225                         /* */
226                         gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(self)), GTK_SELECTION_MULTIPLE);
227                         gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW(self), TRUE);
228                         gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(self), TRUE);
230                         if(self->_priv->do_sort)
231                         {
232                                 int sort_col = cfg_get_single_value_as_int_with_default(config, self->_priv->name, "sort-column",MPDDATA_MODEL_COL_SONG_TITLE);
233                                 int sort_order = cfg_get_single_value_as_int_with_default(config, self->_priv->name, "sort-order", GTK_SORT_ASCENDING);
234                                 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)) {
235                                         gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(gtk_tree_view_get_model(GTK_TREE_VIEW(self))),sort_col, sort_order); 
236                                 }
237                         }
238                 }
240         /**
241          * Save Column Setup
242          */
243         private 
244                 void 
245                 save_column_setup (self)
246                 {
247                         int i=0;
248                         GList *iter,*cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(self));
249                         gchar *conf_pos = NULL;
250                         gchar *conf_show = NULL;
252                         i = g_list_length(cols);
254                         if(i != NUM_COLS)
255                         {
256                                 g_list_free(cols);
257                                 return;
258                         }
259                         conf_pos = g_strdup_printf("%s-colpos", self->_priv->name);
260                         conf_show = g_strdup_printf("%s-colshow", self->_priv->name);
261                         //            conf_size = g_strdup_printf("%s-colsize", self->_priv->name);
262                         i=0;
263                         for(iter = cols; iter; iter = g_list_next(iter))
264                         {
265                                 GtkTreeViewColumn *column = iter->data;
266                                 int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "id"));
267                                 cfg_set_single_value_as_int(config, conf_pos, col_names[id], i);
268                                 cfg_set_single_value_as_int(config, conf_show, col_names[id], gtk_tree_view_column_get_visible(column));
269                                 /* only save width on > 0 columns */
270                                 //if(gtk_tree_view_column_get_width(column) > 0)
271                                 //    cfg_set_single_value_as_int(config, conf_size, col_names[id], gtk_tree_view_column_get_width(column));
272                                 i++;
273                         }
274                         q_free(conf_pos);
275                         q_free(conf_show);
276                         //          q_free(conf_size);
277                         g_list_free(cols);
279                         if(self->_priv->do_sort)
280                         {
281                                 int sort_col;
282                                 GtkSortType sort_order;
283                                 gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(gtk_tree_view_get_model(GTK_TREE_VIEW(self))), &sort_col, &sort_order); 
284                                 cfg_set_single_value_as_int(config, self->_priv->name, "sort-column",sort_col);
285                                 cfg_set_single_value_as_int(config, self->_priv->name, "sort-order", sort_order);
286                         }
287                 }
289         override (G:Object)
290                 void 
291                 dispose (G:Object *obj)
292                 {
293                         Self *self = GMPC_MPDDATA_TREEVIEW(obj);
294                         self_save_column_setup(self);
295                         PARENT_HANDLER(obj);
296                 }
297         private
298                 void
299                 highlight_row (GtkTreeViewColumn *tree_column,
300                                 GtkCellRenderer *cell,
301                                 GtkTreeModel *tree_model,
302                                 GtkTreeIter *iter,
303                                 gpointer data)
304                 {
306                         if(GMPC_IS_MPDDATA_MODEL_PLAYLIST(tree_model) && gmpc_mpddata_model_playlist_is_current_song(tree_model, iter))
307                                 g_object_set(G_OBJECT(cell), "weight", 800,NULL);
308                         else
309                                 g_object_set(G_OBJECT(cell), "weight", 400,NULL);
311                 }
312         private 
313                 void
314                 column_width(self, GParamSpec *argc, GtkTreeViewColumn *column)
315                 {
316                         if(self->_priv->pressed)
317                         {
318                                 int width = gtk_tree_view_column_get_width(column);
319                                 int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "id"));
320                                 gchar *conf_size = g_strdup_printf("%s-colsize", self->_priv->name);
321                                 int w = cfg_get_single_value_as_int(config, conf_size, col_names[id]);
322                                 if(w != width)
323                                 {
324                                         cfg_set_single_value_as_int(config, conf_size, col_names[id],width); 
325                                 }
326                                 q_free(conf_size);
327                         }
328                 }
330         private
331                 GtkTreeViewColumn * 
332                 add_column(self, const char *columnname, int valuerow, int position)
333                 {
334                         GtkCellRenderer *renderer;
335                         GtkTreeViewColumn *column = NULL;
336                         GValue value = {0,};
338                         if(valuerow == MPDDATA_MODEL_COL_ICON_ID)
339                         {
340                                 renderer = gtk_cell_renderer_pixbuf_new();
341                                 g_value_init(&value, G_TYPE_FLOAT);
342                                 g_value_set_float(&value, 0.0);
343                                 g_object_set_property(G_OBJECT(renderer), "xalign", &value); 
345                                 column = gtk_tree_view_column_new ();
346                                 gtk_tree_view_column_pack_start (column, renderer, TRUE);
347                                 gtk_tree_view_column_set_attributes (column,renderer,"icon-name", MPDDATA_MODEL_COL_ICON_ID,NULL);
349                                 gtk_tree_view_column_set_resizable(column, FALSE);
350                                 gtk_tree_view_column_set_fixed_width(column, 20);
351                         }
352                         else{
353                                 renderer = gtk_cell_renderer_text_new();
354                                 column = gtk_tree_view_column_new_with_attributes (_(columnname), renderer,
355                                                 "text", valuerow,NULL);
356                                 g_value_init(&value, G_TYPE_INT);
357                                 g_value_set_int(&value, PANGO_ELLIPSIZE_END);
358                                 g_object_set_property(G_OBJECT(renderer), "ellipsize", &value); 
359                                 gtk_tree_view_column_set_resizable(column, TRUE);
360                                 if(GMPC_IS_MPDDATA_MODEL_PLAYLIST(gtk_tree_view_get_model(GTK_TREE_VIEW(self))))
361                                 {
362                                         g_object_set(G_OBJECT(renderer), "weight-set", TRUE, NULL);
363                                         gtk_tree_view_column_set_cell_data_func (column,renderer,self_highlight_row, NULL, NULL);
364                                 }
366                         }
367                         gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_FIXED);
368                         gtk_tree_view_column_set_reorderable(column, TRUE);
370                         self->_priv->columns[position] = column;
372                         if(self->_priv->do_sort)
373                         {
374                                 gtk_tree_view_column_set_sort_column_id(column,valuerow); 
375                                 gtk_tree_view_column_set_sort_indicator(column, TRUE);
376                         }
378                         return column;
379                 }
380         /**
381          * Opens a column editor 
382          */     
383         public
384                 void
385                 edit_columns(self)
386                 {
387                         GtkWidget *dialog = egg_column_chooser_dialog_new(GTK_TREE_VIEW(self));
388                         gtk_widget_show_all(dialog);
389                         gtk_dialog_run(GTK_DIALOG(dialog));
390                         self_save_column_setup(self);
391                 }
393         override (G:Object)
394                 void
395                 finalize(G:Object *obj)
396                 {
397                         Self *self = SELF(obj);
398                         GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(obj));
399                         if(model)
400                         {
401                                 gtk_tree_view_set_model(GTK_TREE_VIEW(obj),NULL);
402                                 g_object_unref(model);
403                         }
404                         if(self->_priv->tooltip_window)
405                         {
406                                 gtk_widget_destroy(self->_priv->tooltip_window);
407                                 self->_priv->tooltip_window = NULL;
408                         }
409                         if(self->_priv->file)
410                         {
411                                 g_free(self->_priv->file);
412                                 self->_priv->file = NULL;
413                         }
414                         PARENT_HANDLER(obj);
415                 }
417         /****
418          * TREEVIEW POPUP
419          */
420         private gboolean query_tooltip(self,
421                         gint x, gint y, 
422                         gboolean keyboard_tip,
423                         GtkTooltip *tooltip, 
424                         gpointer data)
425         {
426                 GtkTreeView *treeview = GTK_TREE_VIEW(self);
427                 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
428                 GtkTreeIter iter;
429                 GtkTreePath *path = NULL;
430                 mpd_Song *song = NULL;
431                 int show = FALSE;
433                 if(!cfg_get_single_value_as_int_with_default(config, "GmpcTreeView", "show-tooltip", TRUE))
434                         return FALSE;
435                 if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW(treeview), &x, &y,
436                                         keyboard_tip,
437                                         &model, &path, &iter))
438                         return FALSE;
441                 gtk_tree_model_get(model, &iter,MPDDATA_MODEL_COL_MPDSONG, &song, -1);
442                 if(song)
443                 {
444                         show = TRUE;
445                         /* makes it look a bit nicer */
446                         if(self->_priv->file && song->file && strcmp(self->_priv->file, song->file))
447                         {
448                                 show = FALSE;
449                                 g_free(self->_priv->file);self->_priv->file = NULL; 
450                         }
451                         else if(!(self->_priv->file && song->file && strcmp(self->_priv->file, song->file) == 0))
452                         {
453                                 gchar *temp;
455                                 gmpc_metaimage_update_cover_from_song(GMPC_METAIMAGE(self->_priv->tw_image), song);
456                                 if(self->_priv->file)
457                                         g_free(self->_priv->file);
458                                 self->_priv->file = NULL;
459                                 if(song->file)
460                                         self->_priv->file = g_strdup(song->file);
462                                 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_TITLE, &temp, -1);
463                                 gtk_label_set_text(GTK_LABEL(self->_priv->tw_title), temp);
464                                 g_free(temp);
466                                 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_ARTIST,&temp, -1);
467                                 gtk_label_set_text(GTK_LABEL(self->_priv->tw_artist), temp);
468                                 g_free(temp);
470                                 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_ALBUM, &temp, -1);
471                                 gtk_label_set_text(GTK_LABEL(self->_priv->tw_album), temp);
472                                 g_free(temp);
474                                 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_GENRE, &temp, -1);
475                                 gtk_label_set_text(GTK_LABEL(self->_priv->tw_genre), temp);
476                                 g_free(temp);
478                                 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_DATE, &temp, -1);
479                                 gtk_label_set_text(GTK_LABEL(self->_priv->tw_date), temp);
480                                 g_free(temp);
482                                 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_LENGTH_FORMAT, &temp, -1);
483                                 gtk_label_set_text(GTK_LABEL(self->_priv->tw_length), temp);
484                                 g_free(temp);
488                         }
489                 }
490                 gtk_tree_path_free(path);
491                 return show;
492         }
495         private
496                 gboolean
497                 tooltip_expose_event(GtkWidget *widget, GdkEventExpose *event,gpointer data)
498                 {
499                         int stripe_x = 1;
500                         int stripe_y = 1;
501                         int stripe_height = widget->allocation.height;// 128+8; 
502                         GdkColor color;
503                         GtkStyle *style = gtk_widget_get_style(widget);
504                         GdkColor *background_color = &style->base[GTK_STATE_NORMAL];
505                         cairo_t *context;
506                         cairo_surface_t *surface;
507                         cairo_t *cr;
508                         GdkScreen *screen = gtk_window_get_screen(GTK_WINDOW(widget));
509 #ifdef ENABLE_GRADIENT_LOOK
510                         cairo_pattern_t *gradient;
511                         double r, g, b;
512                         int gradient_y = widget->allocation.height - BOTTOM_GRADIENT_HEIGHT;
513 #endif
516                         context = gdk_cairo_create(widget->window);
518                         cairo_set_operator(context, CAIRO_OPERATOR_SOURCE);
519                         surface = cairo_surface_create_similar(cairo_get_target(context),
520                                         CAIRO_CONTENT_COLOR_ALPHA,
521                                         widget->allocation.width,
522                                         widget->allocation.height);
523                         cr = cairo_create(surface);
528                         if (gdk_screen_is_composited(screen))
529                         {
530                                 cairo_set_source_rgba(cr,
531                                                 background_color->red   / 65535.0,
532                                                 background_color->green / 65535.0,
533                                                 background_color->blue  / 65535.0,
534                                                 BACKGROUND_OPACITY);
535                         }
536                         else
537                         {
538                                 gdk_cairo_set_source_color(cr, background_color);
539                         }
541                         cairo_rectangle(cr, 0, 0,
542                                         widget->allocation.width,
543                                         widget->allocation.height);
544                         cairo_fill(cr);
546 #ifdef ENABLE_GRADIENT_LOOK
547                         /* Add a very subtle gradient to the bottom of the notification */
548                         gradient = cairo_pattern_create_linear(0, gradient_y, 0,
549                                         widget->allocation.height);
550                         cairo_pattern_add_color_stop_rgba(gradient, 0, 0, 0, 0, 0);
551                         cairo_pattern_add_color_stop_rgba(gradient, 1, 0, 0, 0, 0.15);
552                         cairo_rectangle(cr, 0, gradient_y, widget->allocation.width,
553                                         BOTTOM_GRADIENT_HEIGHT);
554                         cairo_set_source(cr, gradient);
555                         cairo_fill(cr);
556                         cairo_pattern_destroy(gradient);
557 #endif
559                         cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
560                         cairo_set_line_width(cr, 1.0);
561                         cairo_rectangle(cr, 0.5, 0.5,widget->allocation.width - 0.5, widget->allocation.height - 0.5);
562                         cairo_stroke(cr);
565                         color = style->bg[GTK_STATE_SELECTED];
567                         cairo_rectangle(cr, stripe_x, stripe_y, 160, stripe_height);
569 #ifdef ENABLE_GRADIENT_LOOK
570                         r = color.red   / 65535.0;
571                         g = color.green / 65535.0;
572                         b = color.blue  / 65535.0;
574                         gradient = cairo_pattern_create_linear(stripe_x, 0, 160, 0);
575                         cairo_pattern_add_color_stop_rgba(gradient, 0, r, g, b, 1);
576                         cairo_pattern_add_color_stop_rgba(gradient, 1, r, g, b, 0);
577                         cairo_set_source(cr, gradient);
578                         cairo_fill(cr);
579                         cairo_pattern_destroy(gradient);
580 #else
581                         gdk_cairo_set_source_color(cr, &color);
582                         cairo_fill(cr);
583 #endif
585                         cairo_destroy(cr);
586                         cairo_set_source_surface(context, surface, 0, 0);
587                         cairo_paint(context);
588                         cairo_surface_destroy(surface);
589                         cairo_destroy(context);
591                         return FALSE;//GTK_WIDGET_CLASS(parent_class)->expose_event(widget, event);
592                 }
594         private void enable_tooltip(self)
595         {
596                 gchar *markup = NULL;
597                 GdkScreen *screen;
598                 GdkColormap *colormap;
599                 GtkWidget *treeview = GTK_WIDGET(self);
600                 GtkWidget *table = gtk_table_new(6,2, FALSE);
601                 GtkWidget *vbox = gtk_hbox_new(FALSE, 0);
602                 GtkWidget *label,*ali;
603                 GtkSizeGroup *group  = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
604                 self->_priv->tooltip_window = gtk_window_new(GTK_WINDOW_POPUP);
605                 screen = gtk_window_get_screen(GTK_WINDOW(self->_priv->tooltip_window));
606                 colormap = gdk_screen_get_rgba_colormap(screen);
608                 if (colormap != NULL && gdk_screen_is_composited(screen))
609                 {
610                         gtk_widget_set_colormap(self->_priv->tooltip_window, colormap);
611                 }
614                 gtk_widget_set_size_request(GTK_WIDGET(self->_priv->tooltip_window), 3*128,-1);
616                 gtk_widget_set_app_paintable(self->_priv->tooltip_window, TRUE);
617                 g_signal_connect(G_OBJECT(self->_priv->tooltip_window), "expose-event", G_CALLBACK(self_tooltip_expose_event), self);
619                 gtk_container_add(GTK_CONTAINER(self->_priv->tooltip_window), vbox);
620                 self->_priv->tw_image = gmpc_metaimage_new(META_ALBUM_ART);
622                 ali = gtk_alignment_new(0.0f, 0.0f, 0.0f, 0.0f);
623                 gtk_alignment_set_padding(GTK_ALIGNMENT(ali), 4,4,4,4);
624                 gtk_container_add(GTK_CONTAINER(ali), self->_priv->tw_image);
625                 gmpc_metaimage_set_size(GMPC_METAIMAGE(self->_priv->tw_image), 128);
627                 gtk_box_pack_start(GTK_BOX(vbox), ali, FALSE, FALSE, 0);
629                 gtk_table_set_row_spacings(GTK_TABLE(table), 6);
630                 gtk_table_set_col_spacings(GTK_TABLE(table), 6);
631                 /* set layout up */
632                 gtk_container_set_border_width(GTK_CONTAINER(vbox),1);
633                 gtk_container_set_border_width(GTK_CONTAINER(table), 6);
635                 label = gtk_label_new("");
636                 gtk_size_group_add_widget(group, label);
637                 markup = g_markup_printf_escaped("<b>%s:</b>", _("Title"));
638                 gtk_label_set_markup(GTK_LABEL(label), markup);
639                 g_free(markup);
640                 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
641                 gtk_table_attach(GTK_TABLE(table), label, 0,1,0,1,GTK_FILL, GTK_FILL,0,0);
642                 self->_priv->tw_title = gtk_label_new("n/a");
643                 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_title), 0.0,0.5);
644                 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_title), PANGO_ELLIPSIZE_END);
645                 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_title, 1,2,0,1,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
648                 label = gtk_label_new("");
649                 gtk_size_group_add_widget(group, label);
650                 markup = g_markup_printf_escaped("<b>%s:</b>", _("Artist"));
651                 gtk_label_set_markup(GTK_LABEL(label),markup);
652                 g_free(markup);
653                 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
654                 gtk_table_attach(GTK_TABLE(table), label, 0,1,1,2,GTK_FILL, GTK_FILL,0,0);
655                 self->_priv->tw_artist = gtk_label_new("n/a");
656                 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_artist), 0.0,0.5);
657                 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_artist),PANGO_ELLIPSIZE_END);
658                 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_artist, 1,2,1,2,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
662                 label = gtk_label_new("");
663                 gtk_size_group_add_widget(group, label);
664                 markup = g_markup_printf_escaped("<b>%s:</b>", _("Album"));
665                 gtk_label_set_markup(GTK_LABEL(label),markup);
666                 g_free(markup);
667                 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
668                 gtk_table_attach(GTK_TABLE(table), label, 0,1,2,3,GTK_FILL, GTK_FILL,0,0);
669                 self->_priv->tw_album = gtk_label_new("n/a");
670                 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_album), 0.0,0.5);
671                 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_album),PANGO_ELLIPSIZE_END);
672                 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_album, 1,2,2,3,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
674                 label = gtk_label_new("");
675                 gtk_size_group_add_widget(group, label);
676                 markup = g_markup_printf_escaped("<b>%s:</b>", _("Genre"));
677                 gtk_label_set_markup(GTK_LABEL(label), markup);
678                 g_free(markup);
679                 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
680                 gtk_table_attach(GTK_TABLE(table), label, 0,1,3,4,GTK_FILL, GTK_FILL,0,0);
681                 self->_priv->tw_genre = gtk_label_new("n/a"); 
682                 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_genre), 0.0,0.5);
683                 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_genre),PANGO_ELLIPSIZE_END);
684                 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_genre, 1,2,3,4,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
686                 label = gtk_label_new("");
687                 gtk_size_group_add_widget(group, label);
688                 markup = g_markup_printf_escaped("<b>%s:</b>", _("Date"));
689                 gtk_label_set_markup(GTK_LABEL(label), markup);
690                 g_free(markup);
691                 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
692                 gtk_table_attach(GTK_TABLE(table), label, 0,1,4,5,GTK_FILL, GTK_FILL,0,0);
693                 self->_priv->tw_date = gtk_label_new("n/a"); 
694                 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_date), 0.0,0.5);
695                 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_date),PANGO_ELLIPSIZE_END);
696                 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_date, 1,2,4,5,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
698                 label = gtk_label_new("");
699                 gtk_size_group_add_widget(group, label);
700                 markup = g_markup_printf_escaped("<b>%s:</b>", _("Duration"));
701                 gtk_label_set_markup(GTK_LABEL(label), markup);
702                 g_free(markup);
703                 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
704                 gtk_table_attach(GTK_TABLE(table), label, 0,1,5,6,GTK_FILL, GTK_FILL,0,0);
705                 self->_priv->tw_length = gtk_label_new("n/a"); 
706                 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_length), 0.0,0.5);
707                 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_length),PANGO_ELLIPSIZE_END);
708                 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_length, 1,2,5,6,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
713                 g_object_unref(group);
715                 gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0);
719                 g_signal_connect(G_OBJECT(treeview), 
720                                 "query-tooltip",
721                                 G_CALLBACK(self_query_tooltip),
722                                 NULL); 
723                 gtk_widget_set_tooltip_window(treeview, GTK_WINDOW(self->_priv->tooltip_window));
724                 gtk_widget_show_all(vbox);
725         }
731         /** 
732          * Right mouse click behaviour fix 
733          */
734         private 
735                 gboolean click_fix (self, GdkEventButton *event)
736                 {
737                         GtkTreePath *path = NULL;
738                         self->_priv->pressed = TRUE;
739                         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))
740                         {       
741                                 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(self));
742                                 if(gtk_tree_selection_path_is_selected(sel, path))
743                                 {
744                                         gtk_tree_path_free(path);
745                                         return TRUE;
747                                 }
748                         }
749                         if(path) {
750                                 gtk_tree_path_free(path);
751                         }
752                         return FALSE;
753                 }
755         private 
756                 gboolean click_released (self, GdkEventButton *event)
757                 {
758                         self->_priv->pressed = FALSE;
759                         return FALSE;
760                 }
761         public
762                 void
763                 enable_click_fix(self)
764                 {
765                         g_signal_connect(G_OBJECT(self), "button-press-event", G_CALLBACK(self_click_fix), NULL);
767                         g_signal_connect(G_OBJECT(self), "button-release-event", G_CALLBACK(self_click_released), NULL);
768                 }
769         /**
770          * Copy paste stuff
771          */
772         signal last NONE (POINTER)
773                 void
774                 paste_before(self, GList *items)
775                 {
776                 }
778         signal last NONE (POINTER)
779                 void
780                 paste_after(self, const GList *items)
781                 {
782                 }
783         signal last NONE (NONE)
784                 void
785                 cut(self)
786                 {
787                 }
789         private 
790                 int
791                 paste_key_release_event(self, GdkEventKey *event,gpointer data)
792                 {
793                         if(event->keyval == GDK_Menu) {
794                                 GdkEventButton bevent;
795                                 gboolean value = FALSE;
796                                 bevent.window = NULL;
797                                 bevent.button = 3;
798                                 bevent.time = event->time;
799                                 g_signal_emit_by_name(self, "button-press-event", &bevent, &value,NULL);
800                                 if(!value){ 
801                                         g_signal_emit_by_name(self, "button-release-event", &bevent, &value,NULL);
802                                         }
804                                 return TRUE;
805                         }
806                         if (event->keyval == GDK_c && event->state&GDK_CONTROL_MASK)
807                         {
808                                 self_paste_copy_songs(self, NULL);
809                                 return TRUE;
810                         }
811                         if(paste_queue )
812                         {
813                                 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[PASTE_BEFORE_SIGNAL], 0, TRUE))
814                                 {
815                                         if (event->keyval == GDK_b && event->state&GDK_CONTROL_MASK)
816                                         {
817                                                 self_paste_paste_before_songs(self, NULL);
818                                                 return TRUE;
820                                         }
821                                 }
823                                 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[PASTE_AFTER_SIGNAL], 0, TRUE))
824                                 {
825                                         if (event->keyval == GDK_v && event->state&GDK_CONTROL_MASK)
826                                         {
827                                                 self_paste_paste_after_songs(self, NULL);
828                                                 return TRUE;
829                                         }
830                                 }
831                         }
833                         if (gtk_tree_selection_count_selected_rows (gtk_tree_view_get_selection(GTK_TREE_VIEW(self))) > 0)
834                         {
835                                 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[CUT_SIGNAL], 0, TRUE))
836                                 {
837                                         if (event->keyval == GDK_x && event->state&GDK_CONTROL_MASK)
838                                         {
839                                                 self_paste_cut_songs(self, NULL);
840                                                 return TRUE;
841                                         }
842                                 }
843                         }
844                         return FALSE;
845                 }
846         private
847                 void
848                 paste_cut_songs(self, GtkMenuItem *item)
849                 {
850                         self_paste_copy_songs(self, item);
851                         self_cut(self);
852                 }
853         private
854                 void
855                 paste_paste_after_songs(self, GtkMenuItem *menuitem)
856                 {
857                         self_paste_after(self, g_list_first(paste_queue));
858                         /* free old entries 
859                            g_list_foreach(paste_queue, (GFunc)g_free, NULL);
860                            g_list_free(paste_queue);
861                            paste_queue = NULL;
862                          */
863                 }
865         private
866                 void
867                 paste_paste_before_songs(self, GtkMenuItem *menuitem)
868                 {
869                         self_paste_before(self, g_list_first(paste_queue));
870                         /* free old entries  
871                            g_list_foreach(paste_queue, (GFunc)g_free, NULL);
872                            g_list_free(paste_queue);
873                            paste_queue = NULL;
874                          */
875                 }
877         private 
878                 void
879                 paste_copy_songs(self, GtkMenuItem *menitem)
880                 {
881                         GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(self));
882                         /* free old entries */
883                         g_list_foreach(paste_queue, (GFunc)g_free, NULL);
884                         g_list_free(paste_queue);
885                         paste_queue = NULL;
886                         /* check if where connected */
887                         /* see if there is a row selected */
888                         if (gtk_tree_selection_count_selected_rows (selection) > 0)
889                         {
890                                 GList *list = NULL, *llist = NULL;
891                                 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(self));
892                                 /* start a command list */
893                                 /* grab the selected songs */
894                                 list = gtk_tree_selection_get_selected_rows (selection, &model);
895                                 /* grab the last song that is selected */
896                                 llist = g_list_last (list);
897                                 /* remove every selected song one by one */
898                                 do{
899                                         GtkTreeIter iter;
900                                         gtk_tree_model_get_iter (model, &iter,(GtkTreePath *) llist->data);
901                                         /* Trick that avoids roundtrip to mpd */
902                                         {
903                                                 char *path = NULL;
904                                                 int type = 0;
905                                                 /* this one allready has the pos. */
906                                                 gtk_tree_model_get (model, &iter, 
907                                                                 MPDDATA_MODEL_ROW_TYPE,&type, 
908                                                                 MPDDATA_MODEL_COL_PATH, &path, 
909                                                                 -1);                    
910                                                 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Copying song, into queue: %s\n", path);
911                                                 if(type == MPD_DATA_TYPE_SONG) {
912                                                         paste_queue = g_list_prepend(paste_queue, path);
913                                                 } else if (type == MPD_DATA_TYPE_DIRECTORY) {
914                                                         MpdData *data = mpd_database_get_directory_recursive(connection, path);
915                                                         for(;data; data= mpd_data_get_next(data)){
916                                                                 if(data->type == MPD_DATA_TYPE_SONG) {
917                                                                         paste_queue = g_list_prepend(paste_queue, g_strdup(data->song->file));
918                                                                 }
919                                                         }
920                                                         g_free(path);
921                                                 } else if (type == MPD_DATA_TYPE_PLAYLIST) {
922                                                         MpdData *data = mpd_database_get_playlist_content(connection, path);
923                                                         for(;data; data= mpd_data_get_next(data)){
924                                                                 if(data->type == MPD_DATA_TYPE_SONG) {
925                                                                         paste_queue = g_list_prepend(paste_queue, g_strdup(data->song->file));
926                                                                 }
927                                                         }
928                                                         g_free(path);
929                                                 }
930                                         } 
931                                 } while ((llist = g_list_previous (llist)));
932                                 /* free list */
933                                 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
934                                 g_list_free (list);
935                         }
936                         paste_queue = g_list_reverse(paste_queue);
937                 }
939         public
940                 int 
941                 right_mouse_intergration(self, GtkMenu *menu)
942                 {
943                         int retv = 0;
944                         int i;
945                         GtkWidget *menu_item;
946                         GtkTreeSelection *selection = NULL;
947                         GtkWidget *submenu = gtk_menu_new();
948                         for(i=0; i< num_plugins;i++)
949                         {
950                                 if(gmpc_plugin_get_enabled(plugins[i]))
951                                 {
952                                         retv += gmpc_plugin_browser_song_list_option_menu(plugins[i],self, GTK_MENU(submenu));
953                                 }
954                         }
955                         /* If no submenu item was added, destroy the submenu */
956                         if(!retv) gtk_widget_destroy(submenu);
957                         else{
958                                 GList *temp = gtk_container_get_children(GTK_CONTAINER(menu));
959                                 if(temp){
960                                         menu_item = gtk_separator_menu_item_new();
961                                         g_list_free(temp);
962                                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
963                                 }
964                                 /* Add a tools menu item with the previously generated menu as submenu */
965                                 menu_item = gtk_menu_item_new_with_label(_("Tools"));
966                                 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu);
967                                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
968                         }
971                         /**
972                          * Paste integration
973                          */
974                         
975                         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self));
976                         if(selection && gtk_tree_selection_count_selected_rows(selection))
977                         {
978                                 GList *temp = gtk_container_get_children(GTK_CONTAINER(menu));
979                                 if(temp){
980                                         menu_item = gtk_separator_menu_item_new();
981                                         g_list_free(temp);
982                                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
983                                 }
985                                 menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_COPY, NULL);
986                                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
987                                 g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_paste_copy_songs), self);
988                                 retv++; 
989                         }
990                         if(paste_queue )
991                         {
992                                 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[PASTE_BEFORE_SIGNAL], 0, TRUE))
993                                 {
994                                         menu_item = gtk_image_menu_item_new_with_label(_("Paste before"));
995                                         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
996                                                         gtk_image_new_from_stock(GTK_STOCK_PASTE, GTK_ICON_SIZE_MENU));
997                                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
998                                         g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_paste_paste_before_songs), self);
999                                         retv++;
1000                                 }
1001                                 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[PASTE_AFTER_SIGNAL], 0, TRUE))
1002                                 {
1003                                         menu_item = gtk_image_menu_item_new_with_label(_("Paste after"));
1004                                         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
1005                                                         gtk_image_new_from_stock(GTK_STOCK_PASTE, GTK_ICON_SIZE_MENU));
1006                                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1007                                         g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_paste_paste_after_songs), self);
1008                                         retv++;
1009                                 }
1010                         }
1012                         if (gtk_tree_selection_count_selected_rows (gtk_tree_view_get_selection(GTK_TREE_VIEW(self))) > 0)
1013                         {
1014                                 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[CUT_SIGNAL], 0, TRUE))
1015                                 {
1016                                         menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CUT,NULL);
1017                                         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
1018                                                         gtk_image_new_from_stock(GTK_STOCK_PASTE, GTK_ICON_SIZE_MENU));
1019                                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1020                                         g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_paste_cut_songs), self);
1021                                         retv++;
1022                                 }
1023                         }
1025                         {
1026                                 GList *temp = gtk_container_get_children(GTK_CONTAINER(menu));
1027                                 if(temp){
1028                                         menu_item = gtk_separator_menu_item_new();
1029                                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1030                                         g_list_free(temp);
1031                                         retv++;
1032                                 }
1033                         }
1034                         /** Edit column */
1035                         menu_item = gtk_image_menu_item_new_with_label(_("Edit Columns"));
1036                         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), gtk_image_new_from_stock(GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU));
1037                         g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_edit_columns), self);
1038                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1039                         retv++;
1041                         return retv;
1042                 }
1044         public 
1045                 void
1046                 cleanup(void)
1047                 {
1048                         if(paste_queue)
1049                         {
1050                                 g_list_foreach(paste_queue, (GFunc)g_free, NULL);
1051                                 g_list_free(paste_queue);
1052                         }
1053                         paste_queue = NULL;
1054                 }
1057 /* vim: set noexpandtab ts=4 sw=4 sts=4 tw=120: */