comparison src/audacious/ui_playlist.c @ 2313:3149d4b1a9a9 trunk

[svn] - objective-make autodepend fixes - move all sourcecode into src/ and adjust Makefiles accordingly
author nenolod
date Fri, 12 Jan 2007 11:43:40 -0800
parents
children d88558b0de0a
comparison
equal deleted inserted replaced
2312:e1a5a66fb9cc 2313:3149d4b1a9a9
1 /* Audacious - Cross-platform multimedia player
2 * Copyright (C) 2005-2006 Audacious development team.
3 *
4 * BMP - Cross-platform multimedia player
5 * Copyright (C) 2003-2004 BMP development team.
6 *
7 * Based on XMMS:
8 * Copyright (C) 1998-2003 XMMS development team.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; under version 2 of the License.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 */
23
24 #include "ui_playlist.h"
25
26 #include <glib.h>
27 #include <glib/gi18n.h>
28 #include <gdk/gdk.h>
29 #include <gdk/gdkkeysyms.h>
30 #include <gtk/gtk.h>
31 #include <string.h>
32
33 #include "platform/smartinclude.h"
34
35 #include <unistd.h>
36 #include <errno.h>
37
38 #include "libaudacious/util.h"
39
40 #include "dnd.h"
41 #include "dock.h"
42 #include "ui_equalizer.h"
43 #include "hints.h"
44 #include "input.h"
45 #include "main.h"
46 #include "ui_main.h"
47 #include "ui_manager.h"
48 #include "actions-playlist.h"
49 #include "playback.h"
50 #include "playlist.h"
51 #include "playlist_container.h"
52 #include "playlist_manager.h"
53 #include "util.h"
54
55 #include "icons-stock.h"
56 #include "images/audacious_playlist.xpm"
57
58 GtkWidget *playlistwin;
59
60 PlayList_List *playlistwin_list = NULL;
61 PButton *playlistwin_shade, *playlistwin_close;
62
63 static gboolean playlistwin_resizing = FALSE;
64
65 static GdkPixmap *playlistwin_bg;
66 static GdkBitmap *playlistwin_mask = NULL;
67 static GdkGC *playlistwin_gc;
68
69 static gboolean playlistwin_hint_flag = FALSE;
70
71 static PlaylistSlider *playlistwin_slider = NULL;
72 static TextBox *playlistwin_time_min, *playlistwin_time_sec;
73 static TextBox *playlistwin_info, *playlistwin_sinfo;
74 static SButton *playlistwin_srew, *playlistwin_splay;
75 static SButton *playlistwin_spause, *playlistwin_sstop;
76 static SButton *playlistwin_sfwd, *playlistwin_seject;
77 static SButton *playlistwin_sscroll_up, *playlistwin_sscroll_down;
78
79 static GList *playlistwin_wlist = NULL;
80
81 void playlistwin_select_search_cbt_cb( GtkWidget *called_cbt ,
82 gpointer other_cbt );
83 static gboolean playlistwin_select_search_kp_cb( GtkWidget *entry , GdkEventKey *event ,
84 gpointer searchdlg_win );
85
86 static void playlistwin_draw_frame(void);
87
88
89 gboolean
90 playlistwin_is_shaded(void)
91 {
92 return cfg.playlist_shaded;
93 }
94
95 gint
96 playlistwin_get_width(void)
97 {
98 cfg.playlist_width /= PLAYLISTWIN_WIDTH_SNAP;
99 cfg.playlist_width *= PLAYLISTWIN_WIDTH_SNAP;
100 return cfg.playlist_width;
101 }
102
103 gint
104 playlistwin_get_height_unshaded(void)
105 {
106 gint height;
107 cfg.playlist_height /= PLAYLISTWIN_HEIGHT_SNAP;
108 cfg.playlist_height *= PLAYLISTWIN_HEIGHT_SNAP;
109 height = cfg.playlist_height;
110 return height;
111 }
112
113 gint
114 playlistwin_get_height_shaded(void)
115 {
116 return PLAYLISTWIN_SHADED_HEIGHT;
117 }
118
119 gint
120 playlistwin_get_height(void)
121 {
122 if (playlistwin_is_shaded())
123 return playlistwin_get_height_shaded();
124 else
125 return playlistwin_get_height_unshaded();
126 }
127
128 void
129 playlistwin_get_size(gint * width, gint * height)
130 {
131 if (width)
132 *width = playlistwin_get_width();
133
134 if (height)
135 *height = playlistwin_get_height();
136 }
137
138 static void
139 playlistwin_update_info(Playlist *playlist)
140 {
141 gchar *text, *sel_text, *tot_text;
142 gulong selection, total;
143 gboolean selection_more, total_more;
144
145 playlist_get_total_time(playlist, &total, &selection, &total_more, &selection_more);
146
147 if (selection > 0 || (selection == 0 && !selection_more)) {
148 if (selection > 3600)
149 sel_text =
150 g_strdup_printf("%lu:%-2.2lu:%-2.2lu%s", selection / 3600,
151 (selection / 60) % 60, selection % 60,
152 (selection_more ? "+" : ""));
153 else
154 sel_text =
155 g_strdup_printf("%lu:%-2.2lu%s", selection / 60,
156 selection % 60, (selection_more ? "+" : ""));
157 }
158 else
159 sel_text = g_strdup("?");
160 if (total > 0 || (total == 0 && !total_more)) {
161 if (total > 3600)
162 tot_text =
163 g_strdup_printf("%lu:%-2.2lu:%-2.2lu%s", total / 3600,
164 (total / 60) % 60, total % 60,
165 total_more ? "+" : "");
166 else
167 tot_text =
168 g_strdup_printf("%lu:%-2.2lu%s", total / 60, total % 60,
169 total_more ? "+" : "");
170 }
171 else
172 tot_text = g_strdup("?");
173 text = g_strconcat(sel_text, "/", tot_text, NULL);
174 textbox_set_text(playlistwin_info, text ? text : "");
175 g_free(text);
176 g_free(tot_text);
177 g_free(sel_text);
178 }
179
180 static void
181 playlistwin_update_sinfo(Playlist *playlist)
182 {
183 gchar *posstr, *timestr, *title, *info;
184 gint pos, time;
185
186 pos = playlist_get_position(playlist);
187 title = playlist_get_songtitle(playlist, pos);
188
189 if (!title) {
190 textbox_set_text(playlistwin_sinfo, "");
191 return;
192 }
193
194 convert_title_text(title);
195
196 time = playlist_get_songtime(playlist, pos);
197
198 if (cfg.show_numbers_in_pl)
199 posstr = g_strdup_printf("%d. ", pos + 1);
200 else
201 posstr = g_strdup("");
202
203 if (time != -1) {
204 timestr = g_strdup_printf(" (%d:%-2.2d)", time / 60000,
205 (time / 1000) % 60);
206 }
207 else
208 timestr = g_strdup("");
209
210 info = g_strdup_printf("%s%s%s", posstr, title, timestr);
211
212 g_free(posstr);
213 g_free(title);
214 g_free(timestr);
215
216 textbox_set_text(playlistwin_sinfo, info ? info : "");
217 g_free(info);
218 }
219
220 gboolean
221 playlistwin_item_visible(gint index)
222 {
223 if (index >= playlistwin_list->pl_first
224 && index <
225 (playlistwin_list->pl_first + playlistwin_list->pl_num_visible))
226 return TRUE;
227 return FALSE;
228 }
229
230 gint
231 playlistwin_get_toprow(void)
232 {
233 if (playlistwin_list)
234 return (playlistwin_list->pl_first);
235 return (-1);
236 }
237
238 void
239 playlistwin_set_toprow(gint toprow)
240 {
241 if (playlistwin_list)
242 playlistwin_list->pl_first = toprow;
243 playlistwin_update_list(playlist_get_active());
244 }
245
246 void
247 playlistwin_update_list(Playlist *playlist)
248 {
249 /* this can happen early on. just bail gracefully. */
250 if (playlistwin_list == NULL)
251 return;
252
253 widget_draw(WIDGET(playlistwin_list));
254 widget_draw(WIDGET(playlistwin_slider));
255 playlistwin_update_info(playlist);
256 playlistwin_update_sinfo(playlist);
257 }
258
259 #if 0
260 static void
261 playlistwin_redraw_list(void)
262 {
263 g_return_if_fail(playlistwin_list != NULL);
264
265 draw_widget(playlistwin_list);
266 draw_widget(playlistwin_slider);
267 }
268 #endif
269
270 static void
271 playlistwin_set_mask(void)
272 {
273 GdkGC *gc;
274 GdkColor pattern;
275
276 if (playlistwin_mask)
277 g_object_unref(playlistwin_mask);
278
279 playlistwin_mask =
280 gdk_pixmap_new(playlistwin->window, playlistwin_get_width(),
281 playlistwin_get_height(), 1);
282 gc = gdk_gc_new(playlistwin_mask);
283 pattern.pixel = 1;
284 gdk_gc_set_foreground(gc, &pattern);
285 gdk_draw_rectangle(playlistwin_mask, gc, TRUE, 0, 0,
286 playlistwin_get_width(), playlistwin_get_height());
287 g_object_unref(gc);
288
289 gtk_widget_shape_combine_mask(playlistwin, playlistwin_mask, 0, 0);
290 }
291
292 static void
293 playlistwin_set_geometry_hints(gboolean shaded)
294 {
295 GdkGeometry geometry;
296 GdkWindowHints mask;
297
298 geometry.min_width = PLAYLISTWIN_MIN_WIDTH;
299 geometry.max_width = G_MAXUINT16;
300
301 geometry.width_inc = PLAYLISTWIN_WIDTH_SNAP;
302 geometry.height_inc = PLAYLISTWIN_HEIGHT_SNAP;
303
304 if (shaded) {
305 geometry.min_height = PLAYLISTWIN_SHADED_HEIGHT;
306 geometry.max_height = PLAYLISTWIN_SHADED_HEIGHT;
307 geometry.base_height = PLAYLISTWIN_SHADED_HEIGHT;
308 }
309 else {
310 geometry.min_height = PLAYLISTWIN_MIN_HEIGHT;
311 geometry.max_height = G_MAXUINT16;
312 }
313
314 mask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE | GDK_HINT_RESIZE_INC;
315
316 gtk_window_set_geometry_hints(GTK_WINDOW(playlistwin),
317 playlistwin, &geometry, mask);
318 }
319
320 void
321 playlistwin_set_sinfo_font(gchar *font)
322 {
323 gchar *tmp = NULL, *tmp2 = NULL;
324
325 if(!font)
326 return;
327
328 tmp = g_strdup(font);
329 if(!tmp)
330 return;
331
332 *strrchr(tmp, ' ') = '\0';
333 tmp2 = g_strdup_printf("%s 8", tmp);
334 if(!tmp2)
335 return;
336 textbox_set_xfont(playlistwin_sinfo, cfg.mainwin_use_xfont, tmp2);
337
338 g_free(tmp); g_free(tmp2);
339 }
340
341 void
342 playlistwin_set_sinfo_scroll(gboolean scroll)
343 {
344 GtkWidget *item;
345
346 if(playlistwin_is_shaded())
347 textbox_set_scroll(playlistwin_sinfo, cfg.autoscroll);
348 else
349 textbox_set_scroll(playlistwin_sinfo, FALSE);
350 }
351
352 void
353 playlistwin_set_shade(gboolean shaded)
354 {
355 cfg.playlist_shaded = shaded;
356
357 if (shaded) {
358 playlistwin_set_sinfo_font(cfg.playlist_font);
359 playlistwin_set_sinfo_scroll(cfg.autoscroll);
360 widget_show(WIDGET(playlistwin_sinfo));
361 playlistwin_shade->pb_nx = 128;
362 playlistwin_shade->pb_ny = 45;
363 playlistwin_shade->pb_px = 150;
364 playlistwin_shade->pb_py = 42;
365 playlistwin_close->pb_nx = 138;
366 playlistwin_close->pb_ny = 45;
367 }
368 else {
369 widget_hide(WIDGET(playlistwin_sinfo));
370 playlistwin_set_sinfo_scroll(FALSE);
371 playlistwin_shade->pb_nx = 157;
372 playlistwin_shade->pb_ny = 3;
373 playlistwin_shade->pb_px = 62;
374 playlistwin_shade->pb_py = 42;
375 playlistwin_close->pb_nx = 167;
376 playlistwin_close->pb_ny = 3;
377 }
378
379 dock_shade(dock_window_list, GTK_WINDOW(playlistwin),
380 playlistwin_get_height());
381
382 playlistwin_set_geometry_hints(cfg.playlist_shaded);
383
384 gtk_window_resize(GTK_WINDOW(playlistwin),
385 playlistwin_get_width(),
386 playlistwin_get_height());
387
388 playlistwin_set_mask();
389
390 widget_draw(WIDGET(playlistwin_list));
391 widget_draw(WIDGET(playlistwin_slider));
392
393 draw_playlist_window(TRUE);
394 }
395
396 static void
397 playlistwin_set_shade_menu(gboolean shaded)
398 {
399 GtkAction *action = gtk_action_group_get_action(
400 toggleaction_group_others , "roll up playlist editor" );
401 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , shaded );
402
403 playlistwin_set_shade(shaded);
404 playlistwin_update_list(playlist_get_active());
405 }
406
407 void
408 playlistwin_shade_toggle(void)
409 {
410 playlistwin_set_shade_menu(!cfg.playlist_shaded);
411 }
412
413 static void
414 playlistwin_release(GtkWidget * widget,
415 GdkEventButton * event,
416 gpointer callback_data)
417 {
418 if (event->button == 3)
419 return;
420
421 gdk_pointer_ungrab(GDK_CURRENT_TIME);
422 playlistwin_resizing = FALSE;
423 gdk_flush();
424
425 if (dock_is_moving(GTK_WINDOW(playlistwin)))
426 {
427 dock_move_release(GTK_WINDOW(playlistwin));
428
429 if (cfg.playlist_transparent)
430 playlistwin_update_list(playlist_get_active());
431 }
432 else
433 {
434 handle_release_cb(playlistwin_wlist, widget, event);
435 draw_playlist_window(FALSE);
436 }
437 }
438
439 void
440 playlistwin_scroll(gint num)
441 {
442 playlistwin_list->pl_first += num;
443 playlistwin_update_list(playlist_get_active());
444 }
445
446 void
447 playlistwin_scroll_up_pushed(void)
448 {
449 playlistwin_scroll(-3);
450 }
451
452 void
453 playlistwin_scroll_down_pushed(void)
454 {
455 playlistwin_scroll(3);
456 }
457
458 static void
459 playlistwin_select_all(void)
460 {
461 Playlist *playlist = playlist_get_active();
462
463 playlist_select_all(playlist, TRUE);
464 playlistwin_list->pl_prev_selected = 0;
465 playlistwin_list->pl_prev_min = 0;
466 playlistwin_list->pl_prev_max = playlist_get_length(playlist) - 1;
467 playlistwin_update_list(playlist);
468 }
469
470 static void
471 playlistwin_select_none(void)
472 {
473 playlist_select_all(playlist_get_active(), FALSE);
474 playlistwin_list->pl_prev_selected = -1;
475 playlistwin_list->pl_prev_min = -1;
476 playlistwin_update_list(playlist_get_active());
477 }
478
479 static void
480 playlistwin_select_search(void)
481 {
482 Playlist *playlist = playlist_get_active();
483 GtkWidget *searchdlg_win, *searchdlg_table;
484 GtkWidget *searchdlg_hbox, *searchdlg_logo, *searchdlg_helptext;
485 GtkWidget *searchdlg_entry_track_name, *searchdlg_label_track_name;
486 GtkWidget *searchdlg_entry_album_name, *searchdlg_label_album_name;
487 GtkWidget *searchdlg_entry_file_name, *searchdlg_label_file_name;
488 GtkWidget *searchdlg_entry_performer, *searchdlg_label_performer;
489 GtkWidget *searchdlg_checkbt_clearprevsel;
490 GtkWidget *searchdlg_checkbt_newplaylist;
491 GtkWidget *searchdlg_checkbt_autoenqueue;
492 gint result;
493
494 /* create dialog */
495 searchdlg_win = gtk_dialog_new_with_buttons(
496 _("Search entries in active playlist") , GTK_WINDOW(mainwin) ,
497 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT ,
498 GTK_STOCK_CANCEL , GTK_RESPONSE_REJECT , GTK_STOCK_OK , GTK_RESPONSE_ACCEPT , NULL );
499 /* help text and logo */
500 searchdlg_hbox = gtk_hbox_new( FALSE , 4 );
501 searchdlg_logo = gtk_image_new_from_stock( GTK_STOCK_FIND , GTK_ICON_SIZE_DIALOG );
502 searchdlg_helptext = gtk_label_new( _("Select entries in playlist by filling one or more "
503 "fields. Fields use regular expressions syntax, case-insensitive. If you don't know how "
504 "regular expressions work, simply insert a literal portion of what you're searching for.") );
505 gtk_label_set_line_wrap( GTK_LABEL(searchdlg_helptext) , TRUE );
506 gtk_box_pack_start( GTK_BOX(searchdlg_hbox) , searchdlg_logo , FALSE , FALSE , 0 );
507 gtk_box_pack_start( GTK_BOX(searchdlg_hbox) , searchdlg_helptext , FALSE , FALSE , 0 );
508 /* track name */
509 searchdlg_label_track_name = gtk_label_new( _("Track name: ") );
510 searchdlg_entry_track_name = gtk_entry_new();
511 gtk_misc_set_alignment( GTK_MISC(searchdlg_label_track_name) , 0 , 0.5 );
512 g_signal_connect( G_OBJECT(searchdlg_entry_track_name) , "key-press-event" ,
513 G_CALLBACK(playlistwin_select_search_kp_cb) , searchdlg_win );
514 /* album name */
515 searchdlg_label_album_name = gtk_label_new( _("Album name: ") );
516 searchdlg_entry_album_name = gtk_entry_new();
517 gtk_misc_set_alignment( GTK_MISC(searchdlg_label_album_name) , 0 , 0.5 );
518 g_signal_connect( G_OBJECT(searchdlg_entry_album_name) , "key-press-event" ,
519 G_CALLBACK(playlistwin_select_search_kp_cb) , searchdlg_win );
520 /* artist */
521 searchdlg_label_performer = gtk_label_new( _("Artist: ") );
522 searchdlg_entry_performer = gtk_entry_new();
523 gtk_misc_set_alignment( GTK_MISC(searchdlg_label_performer) , 0 , 0.5 );
524 g_signal_connect( G_OBJECT(searchdlg_entry_performer) , "key-press-event" ,
525 G_CALLBACK(playlistwin_select_search_kp_cb) , searchdlg_win );
526 /* file name */
527 searchdlg_label_file_name = gtk_label_new( _("Filename: ") );
528 searchdlg_entry_file_name = gtk_entry_new();
529 gtk_misc_set_alignment( GTK_MISC(searchdlg_label_file_name) , 0 , 0.5 );
530 g_signal_connect( G_OBJECT(searchdlg_entry_file_name) , "key-press-event" ,
531 G_CALLBACK(playlistwin_select_search_kp_cb) , searchdlg_win );
532 /* some options that control behaviour */
533 searchdlg_checkbt_clearprevsel = gtk_check_button_new_with_label(
534 _("Clear previous selection before searching") );
535 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(searchdlg_checkbt_clearprevsel) , TRUE );
536 searchdlg_checkbt_autoenqueue = gtk_check_button_new_with_label(
537 _("Automatically toggle queue for matching entries") );
538 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(searchdlg_checkbt_autoenqueue) , FALSE );
539 searchdlg_checkbt_newplaylist = gtk_check_button_new_with_label(
540 _("Create a new playlist with matching entries") );
541 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(searchdlg_checkbt_newplaylist) , FALSE );
542 g_signal_connect( G_OBJECT(searchdlg_checkbt_autoenqueue) , "clicked" ,
543 G_CALLBACK(playlistwin_select_search_cbt_cb) , searchdlg_checkbt_newplaylist );
544 g_signal_connect( G_OBJECT(searchdlg_checkbt_newplaylist) , "clicked" ,
545 G_CALLBACK(playlistwin_select_search_cbt_cb) , searchdlg_checkbt_autoenqueue );
546 /* place fields in searchdlg_table */
547 searchdlg_table = gtk_table_new( 8 , 2 , FALSE );
548 gtk_table_set_row_spacing( GTK_TABLE(searchdlg_table) , 0 , 8 );
549 gtk_table_set_row_spacing( GTK_TABLE(searchdlg_table) , 4 , 8 );
550 gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_hbox ,
551 0 , 2 , 0 , 1 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 );
552 gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_label_track_name ,
553 0 , 1 , 1 , 2 , GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 2 );
554 gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_entry_track_name ,
555 1 , 2 , 1 , 2 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 );
556 gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_label_album_name ,
557 0 , 1 , 2 , 3 , GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 2 );
558 gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_entry_album_name ,
559 1 , 2 , 2 , 3 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 );
560 gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_label_performer ,
561 0 , 1 , 3 , 4 , GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 2 );
562 gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_entry_performer ,
563 1 , 2 , 3 , 4 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 );
564 gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_label_file_name ,
565 0 , 1 , 4 , 5 , GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 2 );
566 gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_entry_file_name ,
567 1 , 2 , 4 , 5 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 );
568 gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_checkbt_clearprevsel ,
569 0 , 2 , 5 , 6 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 1 );
570 gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_checkbt_autoenqueue ,
571 0 , 2 , 6 , 7 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 1 );
572 gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_checkbt_newplaylist ,
573 0 , 2 , 7 , 8 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 1 );
574
575 gtk_container_set_border_width( GTK_CONTAINER(searchdlg_table) , 5 );
576 gtk_container_add( GTK_CONTAINER(GTK_DIALOG(searchdlg_win)->vbox) , searchdlg_table );
577 gtk_widget_show_all( searchdlg_win );
578 result = gtk_dialog_run( GTK_DIALOG(searchdlg_win) );
579 switch(result)
580 {
581 case GTK_RESPONSE_ACCEPT:
582 {
583 gint matched_entries_num = 0;
584 /* create a TitleInput tuple with user search data */
585 TitleInput *tuple = g_malloc(sizeof(TitleInput));
586 gchar *searchdata = NULL;
587 searchdata = (gchar*)gtk_entry_get_text( GTK_ENTRY(searchdlg_entry_track_name) );
588 tuple->track_name = ( strcmp(searchdata,"") ) ? g_strdup(searchdata) : NULL;
589 searchdata = (gchar*)gtk_entry_get_text( GTK_ENTRY(searchdlg_entry_album_name) );
590 tuple->album_name = ( strcmp(searchdata,"") ) ? g_strdup(searchdata) : NULL;
591 searchdata = (gchar*)gtk_entry_get_text( GTK_ENTRY(searchdlg_entry_performer) );
592 tuple->performer = ( strcmp(searchdata,"") ) ? g_strdup(searchdata) : NULL;
593 searchdata = (gchar*)gtk_entry_get_text( GTK_ENTRY(searchdlg_entry_file_name) );
594 tuple->file_name = ( strcmp(searchdata,"") ) ? g_strdup(searchdata) : NULL;
595 /* check if previous selection should be cleared before searching */
596 if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(searchdlg_checkbt_clearprevsel)) == TRUE )
597 playlistwin_select_none();
598 /* now send this tuple to the real search function */
599 matched_entries_num = playlist_select_search( playlist , tuple , 0 );
600 /* we do not need the tuple and its data anymore */
601 if ( tuple->track_name != NULL ) g_free( tuple->track_name );
602 if ( tuple->album_name != NULL ) g_free( tuple->album_name );
603 if ( tuple->performer != NULL ) g_free( tuple->performer );
604 if ( tuple->file_name != NULL ) g_free( tuple->file_name );
605 g_free( tuple );
606 playlistwin_update_list(playlist_get_active());
607 /* check if a new playlist should be created after searching */
608 if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(searchdlg_checkbt_newplaylist)) == TRUE )
609 playlist_new_from_selected();
610 /* check if matched entries should be queued */
611 else if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(searchdlg_checkbt_autoenqueue)) == TRUE )
612 playlist_queue(playlist_get_active());
613 break;
614 }
615 default:
616 break;
617 }
618 /* done here :) */
619 gtk_widget_destroy( searchdlg_win );
620 }
621
622 static void
623 playlistwin_inverse_selection(void)
624 {
625 playlist_select_invert_all(playlist_get_active());
626 playlistwin_list->pl_prev_selected = -1;
627 playlistwin_list->pl_prev_min = -1;
628 playlistwin_update_list(playlist_get_active());
629 }
630
631 static void
632 playlistwin_resize(gint width, gint height)
633 {
634 gboolean redraw;
635
636 g_return_if_fail(width > 0 && height > 0);
637
638 cfg.playlist_width = width;
639
640 if (!cfg.playlist_shaded)
641 cfg.playlist_height = height;
642 else
643 height = cfg.playlist_height;
644
645 /* FIXME: why the fsck are we doing this manually? */
646 /* adjust widget positions and sizes */
647
648 widget_resize(WIDGET(playlistwin_list), width - 31, height - 58);
649
650 widget_move(WIDGET(playlistwin_slider), width - 15, 20);
651 widget_resize(WIDGET(playlistwin_slider), 8, height - 58);
652
653 widget_resize(WIDGET(playlistwin_sinfo), width - 35, 14);
654 playlistwin_update_sinfo(playlist_get_active());
655
656 widget_move(WIDGET(playlistwin_shade), width - 21, 3);
657 widget_move(WIDGET(playlistwin_close), width - 11, 3);
658 widget_move(WIDGET(playlistwin_time_min), width - 82, height - 15);
659 widget_move(WIDGET(playlistwin_time_sec), width - 64, height - 15);
660 widget_move(WIDGET(playlistwin_info), width - 143, height - 28);
661 widget_move(WIDGET(playlistwin_srew), width - 144, height - 16);
662 widget_move(WIDGET(playlistwin_splay), width - 138, height - 16);
663 widget_move(WIDGET(playlistwin_spause), width - 128, height - 16);
664 widget_move(WIDGET(playlistwin_sstop), width - 118, height - 16);
665 widget_move(WIDGET(playlistwin_sfwd), width - 109, height - 16);
666 widget_move(WIDGET(playlistwin_seject), width - 100, height - 16);
667 widget_move(WIDGET(playlistwin_sscroll_up), width - 14, height - 35);
668 widget_move(WIDGET(playlistwin_sscroll_down), width - 14, height - 30);
669
670 g_object_unref(playlistwin_bg);
671 playlistwin_bg = gdk_pixmap_new(playlistwin->window, width, height, -1);
672 playlistwin_set_mask();
673
674 widget_list_lock(playlistwin_wlist);
675
676 widget_list_change_pixmap(playlistwin_wlist, playlistwin_bg);
677 playlistwin_draw_frame();
678 widget_list_draw(playlistwin_wlist, &redraw, TRUE);
679 widget_list_clear_redraw(playlistwin_wlist);
680
681 widget_list_unlock(playlistwin_wlist);
682
683 gdk_window_set_back_pixmap(playlistwin->window, playlistwin_bg, 0);
684 gdk_window_clear(playlistwin->window);
685 }
686
687
688
689 static void
690 playlistwin_motion(GtkWidget * widget,
691 GdkEventMotion * event,
692 gpointer callback_data)
693 {
694 GdkEvent *gevent;
695
696 if (dock_is_moving(GTK_WINDOW(playlistwin))) {
697 dock_move_motion(GTK_WINDOW(playlistwin), event);
698 }
699 else {
700 handle_motion_cb(playlistwin_wlist, widget, event);
701 draw_playlist_window(FALSE);
702 }
703 gdk_flush();
704
705 while ((gevent = gdk_event_get()) != NULL) gdk_event_free(gevent);
706 }
707
708 static void
709 playlistwin_enter(GtkWidget * widget,
710 GdkEventMotion * event,
711 gpointer callback_data)
712 {
713 playlistwin_list->pl_tooltips = TRUE;
714 }
715
716 static void
717 playlistwin_leave(GtkWidget * widget,
718 GdkEventMotion * event,
719 gpointer callback_data)
720 {
721 playlistwin_list->pl_tooltips = FALSE;
722 }
723
724 static void
725 playlistwin_show_filebrowser(void)
726 {
727 util_run_filebrowser(NO_PLAY_BUTTON);
728 }
729
730 #if 0
731 static void
732 playlistwin_add_dir_handler(const gchar * dir)
733 {
734 g_free(cfg.filesel_path);
735 cfg.filesel_path = g_strdup(dir);
736 playlist_add_dir(dir);
737 }
738 #endif
739
740 static void
741 playlistwin_fileinfo(void)
742 {
743 Playlist *playlist = playlist_get_active();
744
745 /* Show the first selected file, or the current file if nothing is
746 * selected */
747 GList *list = playlist_get_selected(playlist);
748 if (list) {
749 playlist_fileinfo(playlist, GPOINTER_TO_INT(list->data));
750 g_list_free(list);
751 }
752 else
753 playlist_fileinfo_current(playlist);
754 }
755
756 static void
757 show_playlist_save_error(GtkWindow * parent,
758 const gchar * filename)
759 {
760 GtkWidget *dialog;
761
762 g_return_if_fail(GTK_IS_WINDOW(parent));
763 g_return_if_fail(filename != NULL);
764
765 dialog = gtk_message_dialog_new(GTK_WINDOW(parent),
766 GTK_DIALOG_DESTROY_WITH_PARENT,
767 GTK_MESSAGE_ERROR,
768 GTK_BUTTONS_OK,
769 _("Error writing playlist \"%s\": %s"),
770 filename, strerror(errno));
771
772 gtk_dialog_run(GTK_DIALOG(dialog));
773 gtk_widget_destroy(dialog);
774 }
775
776 static gboolean
777 show_playlist_overwrite_prompt(GtkWindow * parent,
778 const gchar * filename)
779 {
780 GtkWidget *dialog;
781 gint result;
782
783 g_return_val_if_fail(GTK_IS_WINDOW(parent), FALSE);
784 g_return_val_if_fail(filename != NULL, FALSE);
785
786 dialog = gtk_message_dialog_new(GTK_WINDOW(parent),
787 GTK_DIALOG_DESTROY_WITH_PARENT,
788 GTK_MESSAGE_QUESTION,
789 GTK_BUTTONS_YES_NO,
790 _("%s already exist. Continue?"),
791 filename);
792
793 result = gtk_dialog_run(GTK_DIALOG(dialog));
794 gtk_widget_destroy(dialog);
795
796 return (result == GTK_RESPONSE_YES);
797 }
798
799 static void
800 show_playlist_save_format_error(GtkWindow * parent,
801 const gchar * filename)
802 {
803 const gchar *markup =
804 N_("<b><big>Unable to save playlist.</big></b>\n\n"
805 "Unknown file type for '%s'.\n");
806
807 GtkWidget *dialog;
808
809 g_return_if_fail(GTK_IS_WINDOW(parent));
810 g_return_if_fail(filename != NULL);
811
812 dialog =
813 gtk_message_dialog_new_with_markup(GTK_WINDOW(parent),
814 GTK_DIALOG_DESTROY_WITH_PARENT,
815 GTK_MESSAGE_ERROR,
816 GTK_BUTTONS_OK,
817 _(markup),
818 filename);
819 gtk_dialog_run(GTK_DIALOG(dialog));
820 gtk_widget_destroy(dialog);
821 }
822
823 static void
824 playlistwin_save_playlist(const gchar * filename)
825 {
826 PlaylistContainer *plc;
827 gchar *ext = strrchr(filename, '.') + 1;
828
829 plc = playlist_container_find(ext);
830 if (plc == NULL) {
831 show_playlist_save_format_error(GTK_WINDOW(playlistwin), filename);
832 return;
833 }
834
835 str_replace_in(&cfg.playlist_path, g_path_get_dirname(filename));
836
837 if (g_file_test(filename, G_FILE_TEST_IS_REGULAR))
838 if (!show_playlist_overwrite_prompt(GTK_WINDOW(playlistwin), filename))
839 return;
840
841 if (!playlist_save(playlist_get_active(), filename))
842 show_playlist_save_error(GTK_WINDOW(playlistwin), filename);
843 }
844
845 #if 0
846 static void
847 playlistwin_save_current(void)
848 {
849 const gchar *filename;
850
851 if (!(filename = playlist_get_current_name()))
852 return;
853
854 playlistwin_save_playlist(filename);
855 }
856 #endif
857
858 static void
859 playlistwin_load_playlist(const gchar * filename)
860 {
861 Playlist *playlist = playlist_get_active();
862
863 g_return_if_fail(filename != NULL);
864
865 str_replace_in(&cfg.playlist_path, g_strdup(filename));
866
867 playlist_clear(playlist);
868 mainwin_clear_song_info();
869 mainwin_set_info_text();
870
871 playlist_load(playlist, filename);
872 playlist_set_current_name(playlist, filename);
873 }
874
875 static gchar *
876 playlist_file_selection_load(const gchar * title,
877 const gchar * default_filename)
878 {
879 static GtkWidget *dialog = NULL;
880 GtkWidget *button;
881 gchar *filename;
882
883 g_return_val_if_fail(title != NULL, NULL);
884
885 if(!dialog) {
886 dialog = gtk_file_chooser_dialog_new(title, GTK_WINDOW(mainwin),
887 GTK_FILE_CHOOSER_ACTION_OPEN, NULL, NULL);
888
889 if (default_filename)
890 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog),
891 default_filename);
892
893 button = gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CANCEL,
894 GTK_RESPONSE_REJECT);
895 gtk_button_set_use_stock(GTK_BUTTON(button), TRUE);
896 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
897
898 button = gtk_dialog_add_button(GTK_DIALOG(dialog),
899 GTK_STOCK_OPEN,
900 GTK_RESPONSE_ACCEPT);
901 gtk_button_set_use_stock(GTK_BUTTON(button), TRUE);
902 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
903 }
904
905 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
906 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
907 else
908 filename = NULL;
909
910 gtk_widget_hide(dialog);
911 return filename;
912 }
913
914 static gchar *
915 playlist_file_selection_save(const gchar * title,
916 const gchar * default_filename)
917 {
918 static GtkWidget *dialog = NULL;
919 GtkWidget *button;
920 gchar *filename;
921
922 g_return_val_if_fail(title != NULL, NULL);
923
924 if(!dialog) {
925 dialog = gtk_file_chooser_dialog_new(title, GTK_WINDOW(mainwin),
926 GTK_FILE_CHOOSER_ACTION_SAVE, NULL, NULL);
927
928 if (default_filename)
929 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog),
930 default_filename);
931
932 button = gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CANCEL,
933 GTK_RESPONSE_REJECT);
934 gtk_button_set_use_stock(GTK_BUTTON(button), TRUE);
935 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
936
937 button = gtk_dialog_add_button(GTK_DIALOG(dialog),
938 GTK_STOCK_SAVE,
939 GTK_RESPONSE_ACCEPT);
940 gtk_button_set_use_stock(GTK_BUTTON(button), TRUE);
941 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
942 }
943
944 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
945 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
946 else
947 filename = NULL;
948
949 gtk_widget_hide(dialog);
950 return filename;
951 }
952
953 void
954 playlistwin_select_playlist_to_load(const gchar * default_filename)
955 {
956 gchar *filename =
957 playlist_file_selection_load(_("Load Playlist"), default_filename);
958
959 if (filename) {
960 playlistwin_load_playlist(filename);
961 g_free(filename);
962 }
963 }
964
965 static void
966 playlistwin_select_playlist_to_save(const gchar * default_filename)
967 {
968 gchar *dot = NULL, *basename = NULL;
969 gchar *filename =
970 playlist_file_selection_save(_("Save Playlist"), default_filename);
971
972 if (filename) {
973 /* Default to xspf if no filename has extension */
974 basename = g_path_get_basename(filename);
975 dot = strrchr(basename, '.');
976 if( dot == NULL || dot == basename) {
977 gchar *oldname = filename;
978 filename = g_strconcat(oldname, ".xspf", NULL);
979 g_free(oldname);
980 }
981 g_free(basename);
982
983 playlistwin_save_playlist(filename);
984 g_free(filename);
985 }
986 }
987
988 static gboolean
989 inside_sensitive_widgets(gint x, gint y)
990 {
991 return (widget_contains(WIDGET(playlistwin_list), x, y) ||
992 widget_contains(WIDGET(playlistwin_slider), x, y) ||
993 widget_contains(WIDGET(playlistwin_close), x, y) ||
994 widget_contains(WIDGET(playlistwin_shade), x, y) ||
995 widget_contains(WIDGET(playlistwin_time_min), x, y) ||
996 widget_contains(WIDGET(playlistwin_time_sec), x, y) ||
997 widget_contains(WIDGET(playlistwin_info), x, y) ||
998 widget_contains(WIDGET(playlistwin_srew), x, y) ||
999 widget_contains(WIDGET(playlistwin_splay), x, y) ||
1000 widget_contains(WIDGET(playlistwin_spause), x, y) ||
1001 widget_contains(WIDGET(playlistwin_sstop), x, y) ||
1002 widget_contains(WIDGET(playlistwin_sfwd), x, y) ||
1003 widget_contains(WIDGET(playlistwin_seject), x, y) ||
1004 widget_contains(WIDGET(playlistwin_sscroll_up), x, y) ||
1005 widget_contains(WIDGET(playlistwin_sscroll_down), x, y));
1006 }
1007
1008 #define REGION_L(x1,x2,y1,y2) \
1009 (event->x >= (x1) && event->x < (x2) && \
1010 event->y >= cfg.playlist_height - (y1) && \
1011 event->y < cfg.playlist_height - (y2))
1012
1013 #define REGION_R(x1,x2,y1,y2) \
1014 (event->x >= playlistwin_get_width() - (x1) && \
1015 event->x < playlistwin_get_width() - (x2) && \
1016 event->y >= cfg.playlist_height - (y1) && \
1017 event->y < cfg.playlist_height - (y2))
1018
1019 static void
1020 playlistwin_scrolled(GtkWidget * widget,
1021 GdkEventScroll * event,
1022 gpointer callback_data)
1023 {
1024
1025 if (event->direction == GDK_SCROLL_DOWN)
1026 playlistwin_scroll(cfg.scroll_pl_by);
1027
1028 if (event->direction == GDK_SCROLL_UP)
1029 playlistwin_scroll(-cfg.scroll_pl_by);
1030
1031 g_cond_signal(cond_scan);
1032
1033 }
1034
1035 static gboolean
1036 playlistwin_press(GtkWidget * widget,
1037 GdkEventButton * event,
1038 gpointer callback_data)
1039 {
1040 gboolean grab = TRUE;
1041 gint xpos, ypos;
1042 GtkWidget *_menu;
1043 GtkRequisition req;
1044
1045 gtk_window_get_position(GTK_WINDOW(playlistwin), &xpos, &ypos);
1046
1047 if (event->button == 1 && !cfg.show_wm_decorations &&
1048 ((!cfg.playlist_shaded &&
1049 event->x > playlistwin_get_width() - 20 &&
1050 event->y > cfg.playlist_height - 20) ||
1051 (cfg.playlist_shaded &&
1052 event->x >= playlistwin_get_width() - 31 &&
1053 event->x < playlistwin_get_width() - 22))) {
1054
1055 /* NOTE: Workaround for bug #214 */
1056 if (event->type != GDK_2BUTTON_PRESS &&
1057 event->type != GDK_3BUTTON_PRESS) {
1058 /* resize area */
1059 playlistwin_resizing = TRUE;
1060 gtk_window_begin_resize_drag(GTK_WINDOW(widget),
1061 GDK_WINDOW_EDGE_SOUTH_EAST,
1062 event->button,
1063 event->x + xpos, event->y + ypos,
1064 event->time);
1065 }
1066 grab = FALSE;
1067 }
1068 else if (event->button == 1 && REGION_L(12, 37, 29, 11)) {
1069 /* ADD button menu */
1070 gtk_widget_size_request(playlistwin_pladd_menu, &req);
1071 ui_manager_popup_menu_show(GTK_MENU(playlistwin_pladd_menu),
1072 xpos + 12,
1073 (ypos + playlistwin_get_height()) - 8 - req.height,
1074 event->button,
1075 event->time);
1076 grab = FALSE;
1077 }
1078 else if (event->button == 1 && REGION_L(41, 66, 29, 11)) {
1079 /* SUB button menu */
1080 gtk_widget_size_request(playlistwin_pldel_menu, &req);
1081 ui_manager_popup_menu_show(GTK_MENU(playlistwin_pldel_menu),
1082 xpos + 40,
1083 (ypos + playlistwin_get_height()) - 8 - req.height,
1084 event->button,
1085 event->time);
1086 grab = FALSE;
1087 }
1088 else if (event->button == 1 && REGION_L(70, 95, 29, 11)) {
1089 /* SEL button menu */
1090 gtk_widget_size_request(playlistwin_plsel_menu, &req);
1091 ui_manager_popup_menu_show(GTK_MENU(playlistwin_plsel_menu),
1092 xpos + 68,
1093 (ypos + playlistwin_get_height()) - 8 - req.height,
1094 event->button,
1095 event->time);
1096 grab = FALSE;
1097 }
1098 else if (event->button == 1 && REGION_L(99, 124, 29, 11)) {
1099 /* MISC button menu */
1100 gtk_widget_size_request(playlistwin_plsort_menu, &req);
1101 ui_manager_popup_menu_show(GTK_MENU(playlistwin_plsort_menu),
1102 xpos + 100,
1103 (ypos + playlistwin_get_height()) - 8 - req.height,
1104 event->button,
1105 event->time);
1106 grab = FALSE;
1107 }
1108 else if (event->button == 1 && REGION_R(46, 23, 29, 11)) {
1109 /* LIST button menu */
1110 gtk_widget_size_request(playlistwin_pllist_menu, &req);
1111 ui_manager_popup_menu_show(GTK_MENU(playlistwin_pllist_menu),
1112 xpos + playlistwin_get_width() - req.width - 12,
1113 (ypos + playlistwin_get_height()) - 8 - req.height,
1114 event->button,
1115 event->time);
1116 grab = FALSE;
1117 }
1118 else if (event->button == 1 && REGION_R(82, 54, 15, 9)) {
1119 if (cfg.timer_mode == TIMER_ELAPSED)
1120 cfg.timer_mode = TIMER_REMAINING;
1121 else
1122 cfg.timer_mode = TIMER_ELAPSED;
1123 }
1124 else if (event->button == 2 && (event->type == GDK_BUTTON_PRESS) &&
1125 widget_contains(WIDGET(playlistwin_list), event->x, event->y)) {
1126 gtk_selection_convert(widget, GDK_SELECTION_PRIMARY,
1127 GDK_TARGET_STRING, event->time);
1128 }
1129 else if (event->button == 1 && event->type == GDK_BUTTON_PRESS &&
1130 !inside_sensitive_widgets(event->x, event->y) && (cfg.easy_move || event->y < 14))
1131 {
1132 dock_move_press(dock_window_list, GTK_WINDOW(playlistwin), event,
1133 FALSE);
1134 gtk_window_present(GTK_WINDOW(playlistwin));
1135 }
1136 else if (event->button == 1 && event->type == GDK_2BUTTON_PRESS &&
1137 !inside_sensitive_widgets(event->x, event->y)
1138 && event->y < 14) {
1139 /* double click on title bar */
1140 playlistwin_shade_toggle();
1141 if (dock_is_moving(GTK_WINDOW(playlistwin)))
1142 dock_move_release(GTK_WINDOW(playlistwin));
1143 return TRUE;
1144 }
1145 else if (event->button == 3 &&
1146 !(widget_contains(WIDGET(playlistwin_list), event->x, event->y) ||
1147 (event->y >= cfg.playlist_height - 29 &&
1148 event->y < cfg.playlist_height - 11 &&
1149 ((event->x >= 12 && event->x < 37) ||
1150 (event->x >= 41 && event->x < 66) ||
1151 (event->x >= 70 && event->x < 95) ||
1152 (event->x >= 99 && event->x < 124) ||
1153 (event->x >= playlistwin_get_width() - 46 &&
1154 event->x < playlistwin_get_width() - 23))))) {
1155 /*
1156 * Pop up the main menu a few pixels down to avoid
1157 * anything to be selected initially.
1158 */
1159 ui_manager_popup_menu_show(GTK_MENU(mainwin_general_menu), event->x_root,
1160 event->y_root + 2, 3, event->time);
1161 grab = FALSE;
1162 }
1163 else if (event->button == 3 &&
1164 widget_contains(WIDGET(playlistwin_list), event->x, event->y)) {
1165 ui_manager_popup_menu_show(GTK_MENU(playlistwin_popup_menu),
1166 event->x_root, event->y_root + 5,
1167 event->button, event->time);
1168 grab = FALSE;
1169 }
1170 else {
1171 handle_press_cb(playlistwin_wlist, widget, event);
1172 draw_playlist_window(FALSE);
1173 }
1174
1175 if (grab)
1176 gdk_pointer_grab(playlistwin->window, FALSE,
1177 GDK_BUTTON_MOTION_MASK | GDK_BUTTON_RELEASE_MASK |
1178 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
1179 GDK_BUTTON1_MOTION_MASK, NULL, NULL,
1180 GDK_CURRENT_TIME);
1181
1182 return FALSE;
1183 }
1184
1185 static gboolean
1186 playlistwin_focus_in(GtkWidget * widget, GdkEvent * event, gpointer data)
1187 {
1188 playlistwin_close->pb_allow_draw = TRUE;
1189 playlistwin_shade->pb_allow_draw = TRUE;
1190 draw_playlist_window(TRUE);
1191 return FALSE;
1192 }
1193
1194 static gboolean
1195 playlistwin_focus_out(GtkWidget * widget,
1196 GdkEventButton * event, gpointer data)
1197 {
1198 playlistwin_close->pb_allow_draw = FALSE;
1199 playlistwin_shade->pb_allow_draw = FALSE;
1200 draw_playlist_window(TRUE);
1201 return FALSE;
1202 }
1203
1204 static gboolean
1205 playlistwin_configure(GtkWidget * window,
1206 GdkEventConfigure * event, gpointer data)
1207 {
1208 if (!GTK_WIDGET_VISIBLE(window))
1209 return FALSE;
1210
1211 cfg.playlist_x = event->x;
1212 cfg.playlist_y = event->y;
1213
1214 if (playlistwin_resizing) {
1215 if (event->width != playlistwin_get_width() ||
1216 event->height != playlistwin_get_height())
1217 playlistwin_resize(event->width, event->height);
1218 }
1219 return TRUE;
1220 }
1221
1222 void
1223 playlistwin_set_back_pixmap(void)
1224 {
1225 gdk_window_set_back_pixmap(playlistwin->window, playlistwin_bg, 0);
1226 gdk_window_clear(playlistwin->window);
1227 }
1228
1229 static gboolean
1230 playlistwin_delete(GtkWidget * w, gpointer data)
1231 {
1232 playlistwin_hide();
1233 return TRUE;
1234 }
1235
1236 static void
1237 playlistwin_keypress_up_down_handler(PlayList_List * pl,
1238 gboolean up, guint state)
1239 {
1240 Playlist *playlist = playlist_get_active();
1241
1242 if ((state & GDK_MOD1_MASK) && (state & GDK_SHIFT_MASK))
1243 return;
1244 if (!(state & GDK_MOD1_MASK))
1245 playlist_select_all(playlist, FALSE);
1246
1247 if (pl->pl_prev_selected == -1 ||
1248 (!playlistwin_item_visible(pl->pl_prev_selected) &&
1249 !(state & GDK_SHIFT_MASK && pl->pl_prev_min != -1))) {
1250 pl->pl_prev_selected = pl->pl_first;
1251 }
1252 else if (state & GDK_SHIFT_MASK) {
1253 if (pl->pl_prev_min == -1) {
1254 pl->pl_prev_max = pl->pl_prev_selected;
1255 pl->pl_prev_min = pl->pl_prev_selected;
1256 }
1257 pl->pl_prev_max += (up ? -1 : 1);
1258 pl->pl_prev_max =
1259 CLAMP(pl->pl_prev_max, 0, playlist_get_length(playlist) - 1);
1260
1261 pl->pl_first = MIN(pl->pl_first, pl->pl_prev_max);
1262 pl->pl_first = MAX(pl->pl_first, pl->pl_prev_max -
1263 pl->pl_num_visible + 1);
1264 playlist_select_range(playlist, pl->pl_prev_min, pl->pl_prev_max, TRUE);
1265 return;
1266 }
1267 else if (state & GDK_MOD1_MASK) {
1268 if (up)
1269 playlist_list_move_up(pl);
1270 else
1271 playlist_list_move_down(pl);
1272 if (pl->pl_prev_min < pl->pl_first)
1273 pl->pl_first = pl->pl_prev_min;
1274 else if (pl->pl_prev_max >= (pl->pl_first + pl->pl_num_visible))
1275 pl->pl_first = pl->pl_prev_max - pl->pl_num_visible + 1;
1276 return;
1277 }
1278 else if (up)
1279 pl->pl_prev_selected--;
1280 else
1281 pl->pl_prev_selected++;
1282
1283 pl->pl_prev_selected =
1284 CLAMP(pl->pl_prev_selected, 0, playlist_get_length(playlist) - 1);
1285
1286 if (pl->pl_prev_selected < pl->pl_first)
1287 pl->pl_first--;
1288 else if (pl->pl_prev_selected >= (pl->pl_first + pl->pl_num_visible))
1289 pl->pl_first++;
1290
1291 playlist_select_range(playlist, pl->pl_prev_selected, pl->pl_prev_selected, TRUE);
1292 pl->pl_prev_min = -1;
1293 }
1294
1295 /* FIXME: Handle the keys through menu */
1296
1297 static gboolean
1298 playlistwin_keypress(GtkWidget * w, GdkEventKey * event, gpointer data)
1299 {
1300 Playlist *playlist = playlist_get_active();
1301
1302 guint keyval;
1303 gboolean refresh = FALSE;
1304
1305 if (cfg.playlist_shaded)
1306 return FALSE;
1307
1308 switch (keyval = event->keyval) {
1309 case GDK_KP_Up:
1310 case GDK_KP_Down:
1311 case GDK_Up:
1312 case GDK_Down:
1313 playlistwin_keypress_up_down_handler(playlistwin_list,
1314 keyval == GDK_Up
1315 || keyval == GDK_KP_Up,
1316 event->state);
1317 refresh = TRUE;
1318 break;
1319 case GDK_Page_Up:
1320 playlistwin_scroll(-playlistwin_list->pl_num_visible);
1321 refresh = TRUE;
1322 break;
1323 case GDK_Page_Down:
1324 playlistwin_scroll(playlistwin_list->pl_num_visible);
1325 refresh = TRUE;
1326 break;
1327 case GDK_Home:
1328 playlistwin_list->pl_first = 0;
1329 refresh = TRUE;
1330 break;
1331 case GDK_End:
1332 playlistwin_list->pl_first =
1333 playlist_get_length(playlist) - playlistwin_list->pl_num_visible;
1334 refresh = TRUE;
1335 break;
1336 case GDK_Return:
1337 if (playlistwin_list->pl_prev_selected > -1
1338 && playlistwin_item_visible(playlistwin_list->pl_prev_selected)) {
1339 playlist_set_position(playlist, playlistwin_list->pl_prev_selected);
1340 if (!playback_get_playing())
1341 playback_initiate();
1342 }
1343 break;
1344 case GDK_3:
1345 if (event->state & GDK_CONTROL_MASK)
1346 playlistwin_fileinfo();
1347 break;
1348 case GDK_Delete:
1349 if (event->state & GDK_CONTROL_MASK)
1350 playlist_delete(playlist, TRUE);
1351 else
1352 playlist_delete(playlist, FALSE);
1353 break;
1354 case GDK_Insert:
1355 if (event->state & GDK_MOD1_MASK)
1356 mainwin_show_add_url_window();
1357 else
1358 playlistwin_show_filebrowser();
1359 break;
1360 case GDK_Left:
1361 case GDK_KP_Left:
1362 case GDK_KP_7:
1363 if (playlist_get_current_length(playlist) != -1)
1364 playback_seek(CLAMP
1365 (playback_get_time() - 5000, 0,
1366 playlist_get_current_length(playlist)) / 1000);
1367 break;
1368 case GDK_Right:
1369 case GDK_KP_Right:
1370 case GDK_KP_9:
1371 if (playlist_get_current_length(playlist) != -1)
1372 playback_seek(CLAMP
1373 (playback_get_time() + 5000, 0,
1374 playlist_get_current_length(playlist)) / 1000);
1375 break;
1376 case GDK_KP_4:
1377 playlist_prev(playlist);
1378 break;
1379 case GDK_KP_6:
1380 playlist_next(playlist);
1381 break;
1382
1383 case GDK_Escape:
1384 mainwin_minimize_cb();
1385 break;
1386 default:
1387 return FALSE;
1388 }
1389
1390 if (refresh) {
1391 g_cond_signal(cond_scan);
1392 playlistwin_update_list(playlist_get_active());
1393 }
1394
1395 return TRUE;
1396 }
1397
1398 static void
1399 playlistwin_draw_frame(void)
1400 {
1401 gboolean focus =
1402 gtk_window_has_toplevel_focus(GTK_WINDOW(playlistwin)) ||
1403 !cfg.dim_titlebar;
1404
1405 if (cfg.playlist_shaded) {
1406 skin_draw_playlistwin_shaded(bmp_active_skin,
1407 playlistwin_bg, playlistwin_gc,
1408 playlistwin_get_width(), focus);
1409 }
1410 else {
1411 skin_draw_playlistwin_frame(bmp_active_skin,
1412 playlistwin_bg, playlistwin_gc,
1413 playlistwin_get_width(),
1414 cfg.playlist_height, focus);
1415 }
1416 }
1417
1418 void
1419 draw_playlist_window(gboolean force)
1420 {
1421 gboolean redraw;
1422 GList *wl;
1423 Widget *w;
1424
1425 if (force)
1426 playlistwin_draw_frame();
1427
1428 widget_list_lock(playlistwin_wlist);
1429 widget_list_draw(playlistwin_wlist, &redraw, force);
1430
1431 if (redraw || force) {
1432 if (force) {
1433 gdk_window_clear(playlistwin->window);
1434 }
1435 else {
1436 for (wl = playlistwin_wlist; wl; wl = g_list_next(wl)) {
1437 w = WIDGET(wl->data);
1438 if (w->redraw && w->visible) {
1439 gdk_window_clear_area(playlistwin->window, w->x, w->y,
1440 w->width, w->height);
1441 w->redraw = FALSE;
1442 }
1443 }
1444 }
1445
1446 gdk_flush();
1447 }
1448
1449 widget_list_unlock(playlistwin_wlist);
1450 }
1451
1452
1453 void
1454 playlistwin_hide_timer(void)
1455 {
1456 textbox_set_text(playlistwin_time_min, " ");
1457 textbox_set_text(playlistwin_time_sec, " ");
1458 }
1459
1460 void
1461 playlistwin_set_time(gint time, gint length, TimerMode mode)
1462 {
1463 gchar *text, sign;
1464
1465 if (mode == TIMER_REMAINING && length != -1) {
1466 time = length - time;
1467 sign = '-';
1468 }
1469 else
1470 sign = ' ';
1471
1472 time /= 1000;
1473
1474 if (time < 0)
1475 time = 0;
1476 if (time > 99 * 60)
1477 time /= 60;
1478
1479 text = g_strdup_printf("%c%-2.2d", sign, time / 60);
1480 textbox_set_text(playlistwin_time_min, text);
1481 g_free(text);
1482
1483 text = g_strdup_printf("%-2.2d", time % 60);
1484 textbox_set_text(playlistwin_time_sec, text);
1485 g_free(text);
1486 }
1487
1488 static void
1489 playlistwin_drag_motion(GtkWidget * widget,
1490 GdkDragContext * context,
1491 gint x, gint y,
1492 GtkSelectionData * selection_data,
1493 guint info, guint time, gpointer user_data)
1494 {
1495 playlistwin_list->pl_drag_motion = TRUE;
1496 playlistwin_list->drag_motion_x = x;
1497 playlistwin_list->drag_motion_y = y;
1498 playlistwin_update_list(playlist_get_active());
1499 playlistwin_hint_flag = TRUE;
1500 }
1501
1502 static void
1503 playlistwin_drag_end(GtkWidget * widget,
1504 GdkDragContext * context, gpointer user_data)
1505 {
1506 playlistwin_list->pl_drag_motion = FALSE;
1507 playlistwin_hint_flag = FALSE;
1508 playlistwin_update_list(playlist_get_active());
1509 }
1510
1511 static void
1512 playlistwin_drag_data_received(GtkWidget * widget,
1513 GdkDragContext * context,
1514 gint x, gint y,
1515 GtkSelectionData *
1516 selection_data, guint info,
1517 guint time, gpointer user_data)
1518 {
1519 gint pos;
1520 Playlist *playlist = playlist_get_active();
1521
1522 g_return_if_fail(selection_data != NULL);
1523
1524 if (!selection_data->data) {
1525 g_message("Received no DND data!");
1526 return;
1527 }
1528
1529 if (widget_contains(WIDGET(playlistwin_list), x, y)) {
1530 pos = (y - WIDGET(playlistwin_list)->y) /
1531 playlistwin_list->pl_fheight + playlistwin_list->pl_first;
1532
1533 pos = MIN(pos, playlist_get_length(playlist));
1534 playlist_ins_url(playlist, (gchar *) selection_data->data, pos);
1535 }
1536 else
1537 playlist_add_url(playlist, (gchar *) selection_data->data);
1538 }
1539
1540 static void
1541 local_playlist_prev(void)
1542 {
1543 playlist_prev(playlist_get_active());
1544 }
1545
1546 static void
1547 local_playlist_next(void)
1548 {
1549 playlist_next(playlist_get_active());
1550 }
1551
1552 static void
1553 playlistwin_create_widgets(void)
1554 {
1555 gchar *font = NULL, *tmp = NULL;
1556 /* This function creates the custom widgets used by the playlist editor */
1557
1558 /* text box for displaying song title in shaded mode */
1559 playlistwin_sinfo =
1560 create_textbox(&playlistwin_wlist, playlistwin_bg, playlistwin_gc,
1561 4, 4, playlistwin_get_width() - 35, TRUE, SKIN_TEXT);
1562
1563 playlistwin_set_sinfo_font(cfg.playlist_font);
1564
1565 if (!cfg.playlist_shaded)
1566 widget_hide(WIDGET(playlistwin_sinfo));
1567
1568 /* shade/unshade window push button */
1569 if (cfg.playlist_shaded)
1570 playlistwin_shade =
1571 create_pbutton(&playlistwin_wlist, playlistwin_bg,
1572 playlistwin_gc, playlistwin_get_width() - 21, 3,
1573 9, 9, 128, 45, 150, 42,
1574 playlistwin_shade_toggle, SKIN_PLEDIT);
1575 else
1576 playlistwin_shade =
1577 create_pbutton(&playlistwin_wlist, playlistwin_bg,
1578 playlistwin_gc, playlistwin_get_width() - 21, 3,
1579 9, 9, 157, 3, 62, 42, playlistwin_shade_toggle,
1580 SKIN_PLEDIT);
1581
1582 playlistwin_shade->pb_allow_draw = FALSE;
1583
1584 /* close window push button */
1585 playlistwin_close =
1586 create_pbutton(&playlistwin_wlist, playlistwin_bg, playlistwin_gc,
1587 playlistwin_get_width() - 11, 3, 9, 9,
1588 cfg.playlist_shaded ? 138 : 167,
1589 cfg.playlist_shaded ? 45 : 3, 52, 42,
1590 playlistwin_hide, SKIN_PLEDIT);
1591 playlistwin_close->pb_allow_draw = FALSE;
1592
1593 /* playlist list box */
1594 playlistwin_list =
1595 create_playlist_list(&playlistwin_wlist, playlistwin_bg,
1596 playlistwin_gc, 12, 20,
1597 playlistwin_get_width() - 31,
1598 cfg.playlist_height - 58);
1599 playlist_list_set_font(cfg.playlist_font);
1600
1601 /* playlist list box slider */
1602 playlistwin_slider =
1603 create_playlistslider(&playlistwin_wlist, playlistwin_bg,
1604 playlistwin_gc, playlistwin_get_width() - 15,
1605 20, cfg.playlist_height - 58, playlistwin_list);
1606 /* track time (minute) */
1607 playlistwin_time_min =
1608 create_textbox(&playlistwin_wlist, playlistwin_bg, playlistwin_gc,
1609 playlistwin_get_width() - 82,
1610 cfg.playlist_height - 15, 15, FALSE, SKIN_TEXT);
1611
1612 /* track time (second) */
1613 playlistwin_time_sec =
1614 create_textbox(&playlistwin_wlist, playlistwin_bg, playlistwin_gc,
1615 playlistwin_get_width() - 64,
1616 cfg.playlist_height - 15, 10, FALSE, SKIN_TEXT);
1617
1618 /* playlist information (current track length / total track length) */
1619 playlistwin_info =
1620 create_textbox(&playlistwin_wlist, playlistwin_bg, playlistwin_gc,
1621 playlistwin_get_width() - 143,
1622 cfg.playlist_height - 28, 90, FALSE, SKIN_TEXT);
1623
1624 /* mini play control buttons at right bottom corner */
1625
1626 /* rewind button */
1627 playlistwin_srew =
1628 create_sbutton(&playlistwin_wlist, playlistwin_bg, playlistwin_gc,
1629 playlistwin_get_width() - 144,
1630 cfg.playlist_height - 16, 8, 7, local_playlist_prev);
1631
1632 /* play button */
1633 playlistwin_splay =
1634 create_sbutton(&playlistwin_wlist, playlistwin_bg, playlistwin_gc,
1635 playlistwin_get_width() - 138,
1636 cfg.playlist_height - 16, 10, 7, mainwin_play_pushed);
1637
1638 /* pause button */
1639 playlistwin_spause =
1640 create_sbutton(&playlistwin_wlist, playlistwin_bg, playlistwin_gc,
1641 playlistwin_get_width() - 128,
1642 cfg.playlist_height - 16, 10, 7, playback_pause);
1643
1644 /* stop button */
1645 playlistwin_sstop =
1646 create_sbutton(&playlistwin_wlist, playlistwin_bg, playlistwin_gc,
1647 playlistwin_get_width() - 118,
1648 cfg.playlist_height - 16, 9, 7, mainwin_stop_pushed);
1649
1650 /* forward button */
1651 playlistwin_sfwd =
1652 create_sbutton(&playlistwin_wlist, playlistwin_bg, playlistwin_gc,
1653 playlistwin_get_width() - 109,
1654 cfg.playlist_height - 16, 8, 7, local_playlist_next);
1655
1656 /* eject button */
1657 playlistwin_seject =
1658 create_sbutton(&playlistwin_wlist, playlistwin_bg, playlistwin_gc,
1659 playlistwin_get_width() - 100,
1660 cfg.playlist_height - 16, 9, 7, mainwin_eject_pushed);
1661
1662
1663 playlistwin_sscroll_up =
1664 create_sbutton(&playlistwin_wlist, playlistwin_bg, playlistwin_gc,
1665 playlistwin_get_width() - 14,
1666 cfg.playlist_height - 35, 8, 5,
1667 playlistwin_scroll_up_pushed);
1668 playlistwin_sscroll_down =
1669 create_sbutton(&playlistwin_wlist, playlistwin_bg, playlistwin_gc,
1670 playlistwin_get_width() - 14,
1671 cfg.playlist_height - 30, 8, 5,
1672 playlistwin_scroll_down_pushed);
1673
1674 }
1675
1676 static void
1677 selection_received(GtkWidget * widget,
1678 GtkSelectionData * selection_data, gpointer data)
1679 {
1680 if (selection_data->type == GDK_SELECTION_TYPE_STRING &&
1681 selection_data->length > 0)
1682 playlist_add_url(playlist_get_active(), (gchar *) selection_data->data);
1683 }
1684
1685 static void
1686 playlistwin_create_window(void)
1687 {
1688 GdkPixbuf *icon;
1689
1690 playlistwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1691 gtk_window_set_title(GTK_WINDOW(playlistwin), _("Audacious Playlist Editor"));
1692 gtk_window_set_wmclass(GTK_WINDOW(playlistwin), "playlist", "Audacious");
1693 gtk_window_set_role(GTK_WINDOW(playlistwin), "playlist");
1694 gtk_window_set_default_size(GTK_WINDOW(playlistwin),
1695 playlistwin_get_width(),
1696 playlistwin_get_height());
1697 gtk_window_set_resizable(GTK_WINDOW(playlistwin), TRUE);
1698 playlistwin_set_geometry_hints(cfg.playlist_shaded);
1699 dock_window_list = dock_window_set_decorated(dock_window_list,
1700 GTK_WINDOW(playlistwin),
1701 cfg.show_wm_decorations);
1702
1703 gtk_window_set_transient_for(GTK_WINDOW(playlistwin),
1704 GTK_WINDOW(mainwin));
1705 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(playlistwin), TRUE);
1706
1707 icon = gdk_pixbuf_new_from_xpm_data((const gchar **) bmp_playlist_icon);
1708 gtk_window_set_icon(GTK_WINDOW(playlistwin), icon);
1709 g_object_unref(icon);
1710
1711 gtk_widget_set_app_paintable(playlistwin, TRUE);
1712
1713 if (cfg.playlist_x != -1 && cfg.save_window_position)
1714 gtk_window_move(GTK_WINDOW(playlistwin),
1715 cfg.playlist_x, cfg.playlist_y);
1716
1717 gtk_widget_add_events(playlistwin, GDK_POINTER_MOTION_MASK |
1718 GDK_FOCUS_CHANGE_MASK | GDK_BUTTON_MOTION_MASK |
1719 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
1720 GDK_SCROLL_MASK | GDK_VISIBILITY_NOTIFY_MASK);
1721 gtk_widget_realize(playlistwin);
1722
1723 util_set_cursor(playlistwin);
1724
1725 g_signal_connect(playlistwin, "delete_event",
1726 G_CALLBACK(playlistwin_delete), NULL);
1727 g_signal_connect(playlistwin, "button_press_event",
1728 G_CALLBACK(playlistwin_press), NULL);
1729 g_signal_connect(playlistwin, "button_release_event",
1730 G_CALLBACK(playlistwin_release), NULL);
1731 g_signal_connect(playlistwin, "scroll_event",
1732 G_CALLBACK(playlistwin_scrolled), NULL);
1733 g_signal_connect(playlistwin, "motion_notify_event",
1734 G_CALLBACK(playlistwin_motion), NULL);
1735 g_signal_connect(playlistwin, "enter_notify_event",
1736 G_CALLBACK(playlistwin_enter), NULL);
1737 g_signal_connect(playlistwin, "leave_notify_event",
1738 G_CALLBACK(playlistwin_leave), NULL);
1739 g_signal_connect_after(playlistwin, "focus_in_event",
1740 G_CALLBACK(playlistwin_focus_in), NULL);
1741 g_signal_connect_after(playlistwin, "focus_out_event",
1742 G_CALLBACK(playlistwin_focus_out), NULL);
1743 g_signal_connect(playlistwin, "configure_event",
1744 G_CALLBACK(playlistwin_configure), NULL);
1745 g_signal_connect(playlistwin, "style_set",
1746 G_CALLBACK(playlistwin_set_back_pixmap), NULL);
1747
1748 bmp_drag_dest_set(playlistwin);
1749
1750 /* DnD stuff */
1751 g_signal_connect(playlistwin, "drag-leave",
1752 G_CALLBACK(playlistwin_drag_end), NULL);
1753 g_signal_connect(playlistwin, "drag-data-delete",
1754 G_CALLBACK(playlistwin_drag_end), NULL);
1755 g_signal_connect(playlistwin, "drag-end",
1756 G_CALLBACK(playlistwin_drag_end), NULL);
1757 g_signal_connect(playlistwin, "drag-drop",
1758 G_CALLBACK(playlistwin_drag_end), NULL);
1759 g_signal_connect(playlistwin, "drag-data-received",
1760 G_CALLBACK(playlistwin_drag_data_received), NULL);
1761 g_signal_connect(playlistwin, "drag-motion",
1762 G_CALLBACK(playlistwin_drag_motion), NULL);
1763
1764 g_signal_connect(playlistwin, "key_press_event",
1765 G_CALLBACK(playlistwin_keypress), NULL);
1766 g_signal_connect(playlistwin, "selection_received",
1767 G_CALLBACK(selection_received), NULL);
1768
1769 playlistwin_set_mask();
1770 }
1771
1772 void
1773 playlistwin_create(void)
1774 {
1775 Playlist *playlist;
1776 playlistwin_create_window();
1777
1778 /* create GC and back pixmap for custom widget to draw on */
1779 playlistwin_gc = gdk_gc_new(playlistwin->window);
1780 playlistwin_bg = gdk_pixmap_new(playlistwin->window,
1781 playlistwin_get_width(),
1782 playlistwin_get_height_unshaded(), -1);
1783 gdk_window_set_back_pixmap(playlistwin->window, playlistwin_bg, 0);
1784
1785 playlistwin_create_widgets();
1786 playlistwin_update_info(playlist_get_active());
1787
1788 gtk_window_add_accel_group(GTK_WINDOW(playlistwin), ui_manager_get_accel_group());
1789 }
1790
1791
1792 void
1793 playlistwin_show(void)
1794 {
1795 GtkAction *action = gtk_action_group_get_action(
1796 toggleaction_group_others , "show playlist editor" );
1797 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , TRUE );
1798
1799 tbutton_set_toggled(mainwin_pl, TRUE);
1800 cfg.playlist_visible = TRUE;
1801
1802 playlistwin_set_toprow(0);
1803 playlist_check_pos_current(playlist_get_active());
1804
1805 gtk_widget_show(playlistwin);
1806 }
1807
1808 void
1809 playlistwin_hide(void)
1810 {
1811 GtkAction *action = gtk_action_group_get_action(
1812 toggleaction_group_others , "show playlist editor" );
1813 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , FALSE );
1814
1815 gtk_widget_hide(playlistwin);
1816 tbutton_set_toggled(mainwin_pl, FALSE);
1817 cfg.playlist_visible = FALSE;
1818
1819 gtk_window_present(GTK_WINDOW(mainwin));
1820 gtk_widget_grab_focus(mainwin);
1821 }
1822
1823 void action_playlist_track_info(void)
1824 {
1825 playlistwin_fileinfo();
1826 }
1827
1828 void action_queue_toggle(void)
1829 {
1830 playlist_queue(playlist_get_active());
1831 }
1832
1833 void action_playlist_sort_by_playlist_entry(void)
1834 {
1835 Playlist *playlist = playlist_get_active();
1836
1837 playlist_sort(playlist, PLAYLIST_SORT_PLAYLIST);
1838 playlistwin_update_list(playlist);
1839 }
1840
1841 void action_playlist_sort_by_track_number(void)
1842 {
1843 Playlist *playlist = playlist_get_active();
1844
1845 playlist_sort(playlist, PLAYLIST_SORT_TRACK);
1846 playlistwin_update_list(playlist);
1847 }
1848
1849 void action_playlist_sort_by_title(void)
1850 {
1851 Playlist *playlist = playlist_get_active();
1852
1853 playlist_sort(playlist, PLAYLIST_SORT_TITLE);
1854 playlistwin_update_list(playlist);
1855 }
1856
1857 void action_playlist_sort_by_artist(void)
1858 {
1859 Playlist *playlist = playlist_get_active();
1860
1861 playlist_sort(playlist, PLAYLIST_SORT_ARTIST);
1862 playlistwin_update_list(playlist);
1863 }
1864
1865 void action_playlist_sort_by_full_path(void)
1866 {
1867 Playlist *playlist = playlist_get_active();
1868
1869 playlist_sort(playlist, PLAYLIST_SORT_PATH);
1870 playlistwin_update_list(playlist);
1871 }
1872
1873 void action_playlist_sort_by_date(void)
1874 {
1875 Playlist *playlist = playlist_get_active();
1876
1877 playlist_sort(playlist, PLAYLIST_SORT_DATE);
1878 playlistwin_update_list(playlist);
1879 }
1880
1881 void action_playlist_sort_by_filename(void)
1882 {
1883 Playlist *playlist = playlist_get_active();
1884
1885 playlist_sort(playlist, PLAYLIST_SORT_FILENAME);
1886 playlistwin_update_list(playlist);
1887 }
1888
1889 void action_playlist_sort_selected_by_playlist_entry(void)
1890 {
1891 Playlist *playlist = playlist_get_active();
1892
1893 playlist_sort_selected(playlist, PLAYLIST_SORT_PLAYLIST);
1894 playlistwin_update_list(playlist);
1895 }
1896
1897 void action_playlist_sort_selected_by_track_number(void)
1898 {
1899 Playlist *playlist = playlist_get_active();
1900
1901 playlist_sort_selected(playlist, PLAYLIST_SORT_TRACK);
1902 playlistwin_update_list(playlist);
1903 }
1904
1905 void action_playlist_sort_selected_by_title(void)
1906 {
1907 Playlist *playlist = playlist_get_active();
1908
1909 playlist_sort_selected(playlist, PLAYLIST_SORT_TITLE);
1910 playlistwin_update_list(playlist);
1911 }
1912
1913 void action_playlist_sort_selected_by_artist(void)
1914 {
1915 Playlist *playlist = playlist_get_active();
1916
1917 playlist_sort_selected(playlist, PLAYLIST_SORT_ARTIST);
1918 playlistwin_update_list(playlist);
1919 }
1920
1921 void action_playlist_sort_selected_by_full_path(void)
1922 {
1923 Playlist *playlist = playlist_get_active();
1924
1925 playlist_sort_selected(playlist, PLAYLIST_SORT_PATH);
1926 playlistwin_update_list(playlist);
1927 }
1928
1929 void action_playlist_sort_selected_by_date(void)
1930 {
1931 Playlist *playlist = playlist_get_active();
1932
1933 playlist_sort_selected(playlist, PLAYLIST_SORT_DATE);
1934 playlistwin_update_list(playlist);
1935 }
1936
1937 void action_playlist_sort_selected_by_filename(void)
1938 {
1939 Playlist *playlist = playlist_get_active();
1940
1941 playlist_sort_selected(playlist, PLAYLIST_SORT_FILENAME);
1942 playlistwin_update_list(playlist);
1943 }
1944
1945 void action_playlist_randomize_list(void)
1946 {
1947 Playlist *playlist = playlist_get_active();
1948
1949 playlist_random(playlist);
1950 playlistwin_update_list(playlist);
1951 }
1952
1953 void action_playlist_reverse_list(void)
1954 {
1955 Playlist *playlist = playlist_get_active();
1956
1957 playlist_reverse(playlist);
1958 playlistwin_update_list(playlist);
1959 }
1960
1961 void
1962 action_playlist_clear_queue(void)
1963 {
1964 playlist_clear_queue(playlist_get_active());
1965 }
1966
1967 void
1968 action_playlist_remove_unavailable(void)
1969 {
1970 playlist_remove_dead_files(playlist_get_active());
1971 }
1972
1973 void
1974 action_playlist_remove_dupes_by_title(void)
1975 {
1976 playlist_remove_duplicates(playlist_get_active(), PLAYLIST_DUPS_TITLE);
1977 }
1978
1979 void
1980 action_playlist_remove_dupes_by_filename(void)
1981 {
1982 playlist_remove_duplicates(playlist_get_active(), PLAYLIST_DUPS_FILENAME);
1983 }
1984
1985 void
1986 action_playlist_remove_dupes_by_full_path(void)
1987 {
1988 playlist_remove_duplicates(playlist_get_active(), PLAYLIST_DUPS_PATH);
1989 }
1990
1991 void
1992 action_playlist_remove_all(void)
1993 {
1994 playlist_clear(playlist_get_active());
1995
1996 /* XXX -- should this really be coupled here? -nenolod */
1997 mainwin_clear_song_info();
1998 mainwin_set_info_text();
1999 }
2000
2001 void
2002 action_playlist_remove_selected(void)
2003 {
2004 playlist_delete(playlist_get_active(), FALSE);
2005 }
2006
2007 void
2008 action_playlist_remove_unselected(void)
2009 {
2010 playlist_delete(playlist_get_active(), TRUE);
2011 }
2012
2013 void
2014 action_playlist_add_files(void)
2015 {
2016 util_run_filebrowser(NO_PLAY_BUTTON);
2017 }
2018
2019 void add_medium(void); /* XXX */
2020
2021 void
2022 action_playlist_add_cd(void)
2023 {
2024 add_medium();
2025 }
2026
2027 void
2028 action_playlist_add_url(void)
2029 {
2030 mainwin_show_add_url_window();
2031 }
2032
2033 void
2034 action_playlist_new( void )
2035 {
2036 Playlist *new_pl = playlist_new();
2037 playlist_add_playlist(new_pl);
2038 playlist_select_playlist(new_pl);
2039 }
2040
2041 void
2042 action_playlist_prev( void )
2043 {
2044 playlist_select_prev();
2045 }
2046
2047 void
2048 action_playlist_next( void )
2049 {
2050 playlist_select_next();
2051 }
2052
2053 void
2054 action_playlist_delete( void )
2055 {
2056 playlist_remove_playlist( playlist_get_active() );
2057 }
2058
2059 void
2060 action_playlist_save_list(void)
2061 {
2062 Playlist *playlist = playlist_get_active();
2063
2064 playlistwin_select_playlist_to_save(playlist_get_current_name(playlist));
2065 }
2066
2067 void
2068 action_playlist_save_default_list(void)
2069 {
2070 Playlist *playlist = playlist_get_active();
2071
2072 playlist_save(playlist, bmp_paths[BMP_PATH_PLAYLIST_FILE]);
2073 }
2074
2075 void
2076 action_playlist_load_list(void)
2077 {
2078 Playlist *playlist = playlist_get_active();
2079
2080 playlistwin_select_playlist_to_load(playlist_get_current_name(playlist));
2081 }
2082
2083 void
2084 action_playlist_refresh_list(void)
2085 {
2086 Playlist *playlist = playlist_get_active();
2087
2088 playlist_read_info_selection(playlist);
2089 playlistwin_update_list(playlist);
2090 }
2091
2092 void
2093 action_open_list_manager(void)
2094 {
2095 playlist_manager_ui_show();
2096 }
2097
2098 void
2099 action_playlist_search_and_select(void)
2100 {
2101 playlistwin_select_search();
2102 }
2103
2104 void
2105 action_playlist_invert_selection(void)
2106 {
2107 playlistwin_inverse_selection();
2108 }
2109
2110 void
2111 action_playlist_select_none(void)
2112 {
2113 playlistwin_select_none();
2114 }
2115
2116 void
2117 action_playlist_select_all(void)
2118 {
2119 playlistwin_select_all();
2120 }
2121
2122
2123
2124 /* playlistwin_select_search callback functions
2125 placed here to avoid making the code messier :) */
2126 void
2127 playlistwin_select_search_cbt_cb( GtkWidget *called_cbt , gpointer other_cbt )
2128 {
2129 if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(called_cbt) ) == TRUE )
2130 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(other_cbt) , FALSE );
2131 return;
2132 }
2133
2134 static gboolean
2135 playlistwin_select_search_kp_cb( GtkWidget *entry , GdkEventKey *event ,
2136 gpointer searchdlg_win )
2137 {
2138 switch (event->keyval)
2139 {
2140 case GDK_Return:
2141 gtk_dialog_response( GTK_DIALOG(searchdlg_win) , GTK_RESPONSE_ACCEPT );
2142 return TRUE;
2143 default:
2144 return FALSE;
2145 }
2146 }