Re: xmms plugin updated
Mario Streiber <[email protected]>
| Newsgroups | gmane.comp.desktop.xfce.goodies.devel |
|---|---|
| Message-ID | <[email protected]> |
On Tue, 26 Apr 2005 13:58:29 +0200 Mario Streiber <[email protected]> wrote: > > xmms_plugin.h does not exists. > > Yes sorry I forgot to send it in my first mail. Here it is once more. Oh and the .c file contains a bug which makes the panel crash as soon as you scroll to change the volume. Here is a fixed version. Mario
xmms_plugin.c
(text/plain, 21.2 KB)
/* * Copyright (c) 2003 Patrick van Staveren <[email protected]> * Copyright (c) 2005 Kemal Ilgar Eroglu <[email protected]> * Copyright (c) 2005 Mario Streiber <[email protected]> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/wait.h> #include <gtk/gtk.h> #include <libxfce4util/i18n.h> #include <libxfcegui4/dialogs.h> #include <panel/plugins.h> #include <panel/xfce.h> #include <xmmsctrl.h> #include "xmms_plugin.h" /* displays or hides the xmms windows */ static void display_xmms(plugin_data *pd, gboolean show) { /* do nothing if xmms is not running */ if (!xmms_remote_is_running(pd->xmms_session)) return; if (show) { /* display xmms windows based on their prior status */ if (pd->show_mw) xmms_remote_main_win_toggle(pd->xmms_session, TRUE); if (pd->show_pl) xmms_remote_pl_win_toggle (pd->xmms_session, TRUE); if (pd->show_eq) xmms_remote_eq_win_toggle (pd->xmms_session, TRUE); pd->xmmsvisible = TRUE; } else { /* save status of each xmms window */ pd->show_mw = xmms_remote_is_main_win(pd->xmms_session); pd->show_pl = xmms_remote_is_pl_win (pd->xmms_session); pd->show_eq = xmms_remote_is_eq_win (pd->xmms_session); /* make sure at least the main window is shown on redisplay */ if (!(pd->show_pl || pd->show_eq)) pd->show_mw = TRUE; /* hide all */ xmms_remote_main_win_toggle(pd->xmms_session, FALSE); xmms_remote_pl_win_toggle (pd->xmms_session, FALSE); xmms_remote_eq_win_toggle (pd->xmms_session, FALSE); pd->xmmsvisible = FALSE; } } /* callback to jump to the previous song in the playlist */ static void prev(GtkWidget *widget, GdkEventButton* event, gpointer data) { if (event->button != 1) return; xmms_remote_playlist_prev(((plugin_data*) data)->xmms_session); } /* callback to start playing; if xmms is not running it will be started */ static void play(GtkWidget *widget, GdkEventButton* event, gpointer data) { plugin_data *pd = (plugin_data*) data; int i=0; pid_t pid; int status; if (event->button != 1) return; /* start xmms and hide its windows if not already running */ if (!xmms_remote_is_running(pd->xmms_session)) { if (exec_command("xmms -p")) { while (!xmms_remote_is_running(pd->xmms_session) && (i <= 5)) { sleep(1); i++; } } if ((i < 5) && (!pd->xmmsvisible)) display_xmms(pd, FALSE); } else xmms_remote_play(pd->xmms_session); } /* callback for pausing xmms */ static void paus(GtkWidget *widget, GdkEventButton* event, gpointer data) { if (event->button != 1) return; xmms_remote_pause(((plugin_data*) data)->xmms_session); } /* callback for stopping xmms */ static void stop(GtkWidget *widget, GdkEventButton* event, gpointer data) { if (event->button != 1) return; xmms_remote_stop(((plugin_data*) data)->xmms_session); } /* callback to jump to the next song in the playlist */ static void next(GtkWidget *widget, GdkEventButton* event, gpointer data) { if (event->button != 1) return; xmms_remote_playlist_next(((plugin_data*) data)->xmms_session); } /* callback for clicking on the progress bar */ /* button 1: jump to time in the current song */ /* button 2: toggle xmms window visibility */ static void pbar_click(GtkWidget* widget, GdkEventButton* event, gpointer data) { gint width, time, total; plugin_data *pd = (plugin_data *) data; switch (event->button) { case 1: // jump to time within this song width = pd->pbar->allocation.width; total = xmms_remote_get_playlist_time(pd->xmms_session, xmms_remote_get_playlist_pos(pd->xmms_session)); time = (int) (event->x * total / width); xmms_remote_jump_to_time(pd->xmms_session, time); break; case 2: // toggle xmms window visibility display_xmms(pd, !pd->xmmsvisible); } } /* callback for changing the volume when using the scroll wheel */ static void box_scroll(GtkWidget* widget, GdkEventScroll* event, gpointer data) { gint vl, vr; plugin_data *pd = (plugin_data*) data; xmms_remote_get_volume(pd->xmms_session, &vl, &vr); if(event->direction == GDK_SCROLL_UP) xmms_remote_set_volume(pd->xmms_session, vl+8, vr+8); else xmms_remote_set_volume(pd->xmms_session, vl-8, vr-8); } /* timeout function to update the plugin widgets */ gboolean pbar_label_update(gpointer data) { plugin_data *pd = (plugin_data*) data; GtkAdjustment *adj; gchar *title, *tooltip; gint sp, len, time = 1, pl_pos, play_time = 0; PangoAttribute *attr; gboolean running, playing; /* check xmms status */ running = xmms_remote_is_running(pd->xmms_session); playing = (running && xmms_remote_is_playing(pd->xmms_session)); if (running) { /* get playlist position and song length */ pl_pos = xmms_remote_get_playlist_pos(pd->xmms_session); time = xmms_remote_get_playlist_time(pd->xmms_session, pl_pos) / 1000; } else pl_pos = -1; /* update tooltip and song title */ if (pd->playlist_position != pl_pos) { pd->playlist_position = pl_pos; pd->title_scroll_position = 0; if (running) tooltip = g_strdup_printf("%d: %s (%d:%02d)", pl_pos, xmms_remote_get_playlist_title(pd->xmms_session, pl_pos), time / 60, time % 60); else tooltip = g_strdup_printf(TITLE_STRING); title = g_strdup_printf("%s +++ %s +++", tooltip, tooltip); gtk_tooltips_set_tip(pd->tooltip, GTK_WIDGET(pd->base), tooltip, NULL); pd->labelattr->start_index = 0; pd->labelattr->end_index = strlen(title); gtk_label_set_attributes(GTK_LABEL(pd->label), pd->labelattrlist); gtk_label_set_text(GTK_LABEL(pd->label), title); g_free(title); g_free(tooltip); } /* update progress bar */ if (playing) play_time = xmms_remote_get_output_time(pd->xmms_session) / 1000; if (pd->play_time != play_time) { gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pd->pbar), (gdouble) play_time / time); pd->play_time = play_time; } /* scroll song title */ adj = gtk_viewport_get_hadjustment(GTK_VIEWPORT(pd->viewport)); len = pd->label->allocation.width / 2; sp = pd->title_scroll_position - pd->step_delay; sp = (sp < 0) ? 0 : sp; sp = (len > 0) ? sp % len : 0; gtk_adjustment_set_value(adj, sp); pd->title_scroll_position += pd->scroll_step; /* set up new timer and destroy old if new scroll speed has been set */ if (pd->timer_reset) { g_source_remove(pd->timeout); pd->timeout = g_timeout_add(1000 / pd->scroll_speed, pbar_label_update, pd); pd->timer_reset = FALSE; return FALSE; } return TRUE; } /* adds a new button with image and callback to the parent box */ static void new_button_with_img(GtkWidget *box, gchar *filename, gpointer cb, gpointer data) { GtkWidget *image, *eventbox; eventbox = gtk_event_box_new(); image = gtk_image_new_from_file(filename); gtk_widget_show (image); gtk_container_add (GTK_CONTAINER(eventbox), image); gtk_widget_set_events (eventbox, GDK_BUTTON_PRESS_MASK); g_signal_connect (G_OBJECT(eventbox), "button_press_event", G_CALLBACK(cb), data); gtk_box_pack_start (GTK_BOX(box), eventbox, DOEXPAND, DOFILL, PADDING); } /* creates the plugin widgets */ gboolean xmms_plugin_control_new(Control *ctrl) { GtkWidget *button, *box, *boxMain, *pbar, *viewport, *eventbox, *label; plugin_data *pd; gint i; gchar *title = TITLE_STRING" +++ "TITLE_STRING" +++ "; pd = g_new(plugin_data, 1); /* These defaults will be overwritten by read config */ pd->titletextsize = TITLE_SIZE; pd->title_scroll_position = 0; pd->scroll_speed = SCROLL_SPEED; pd->scroll_step = SCROLL_STEP; pd->step_delay = STEP_DELAY; pd->scroll_delay = SCROLL_DELAY; pd->playlist_position = -1; pd->play_time = -1; pd->xmmsvisible = FALSE; pd->xmms_session = 0; pd->timeout = 0; pd->timer_reset = FALSE; pd->show_scrolledtitle = TRUE; pd->tooltip = gtk_tooltips_new(); pd->labelattrlist = pango_attr_list_new(); pd->labelattr = pango_attr_size_new(pd->titletextsize * PANGO_SCALE); pd->labelattr->start_index = 0; pd->labelattr->end_index = strlen(title); pango_attr_list_insert (pd->labelattrlist, pd->labelattr); /* add scrolling callback for the plugin base widget */ pd->base = ctrl->base; gtk_widget_add_events(GTK_WIDGET(ctrl->base), GDK_SCROLL_MASK); g_signal_connect(G_OBJECT(ctrl->base),"scroll_event",G_CALLBACK(box_scroll), pd); gtk_tooltips_set_tip (pd->tooltip, GTK_WIDGET(ctrl->base), TITLE_STRING, NULL); /* main container for the plugin widgets */ boxMain = gtk_vbox_new(FALSE, 0); /* label for the song title */ eventbox = gtk_event_box_new(); label = gtk_label_new(title); gtk_label_set_line_wrap (GTK_LABEL(label), FALSE); gtk_container_add (GTK_CONTAINER(eventbox), label); gtk_widget_set_events (eventbox, GDK_BUTTON_PRESS_MASK); gtk_label_set_attributes (GTK_LABEL(label), pd->labelattrlist); /* viewport widget that manages the scrolling */ viewport = gtk_viewport_new(NULL, NULL); gtk_viewport_set_shadow_type (GTK_VIEWPORT(viewport), GTK_SHADOW_NONE); gtk_container_add (GTK_CONTAINER(viewport), eventbox); gtk_widget_set_size_request (viewport, 0, -1); gtk_box_pack_start (GTK_BOX(boxMain), viewport, DOEXPAND, DOFILL, PADDING); /* the progress bar */ pbar = gtk_progress_bar_new(); gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR(pbar), GTK_PROGRESS_CONTINUOUS); gtk_widget_set_size_request (pbar, 0, -1); gtk_widget_set_events (pbar, GDK_BUTTON_PRESS_MASK); g_signal_connect (G_OBJECT(pbar), "button_press_event", G_CALLBACK(pbar_click), pd); gtk_box_pack_start (GTK_BOX(boxMain), pbar, DOEXPAND, DOFILL, PADDING); pd->boxMain = boxMain; pd->viewport = viewport; pd->label = label; pd->pbar = pbar; /* box that contains the xmms control buttons */ box = gtk_hbox_new(FALSE, 0); new_button_with_img(box, PREV, G_CALLBACK(prev), pd); new_button_with_img(box, PLAY, G_CALLBACK(play), pd); new_button_with_img(box, PAUS, G_CALLBACK(paus), pd); new_button_with_img(box, STOP, G_CALLBACK(stop), pd); new_button_with_img(box, NEXT, G_CALLBACK(next), pd); gtk_box_pack_start (GTK_BOX(boxMain), box, DOEXPAND, DOFILL, PADDING); gtk_container_set_border_width (GTK_CONTAINER(boxMain), 2); gtk_container_add (GTK_CONTAINER(ctrl->base), boxMain); gtk_widget_show_all(boxMain); pd->timeout = g_timeout_add(1000 / pd->scroll_speed, pbar_label_update, pd); ctrl->data = (gpointer) pd; ctrl->with_popup = FALSE; return(TRUE); } /* frees all resources used by the plugin (I hope :-) */ static void xmms_plugin_free(Control *ctrl) { plugin_data *pd; g_return_if_fail(ctrl != NULL); g_return_if_fail(ctrl-> data != NULL); pd = (plugin_data*) ctrl->data; /* remove timeout */ if (pd->timeout) g_source_remove(pd->timeout); /* destroy all widgets */ gtk_widget_destroy(pd->boxMain); /* destroy text attribute for the label widget */ pango_attribute_destroy(pd->labelattr); /* let xmms exit */ xmms_remote_quit(pd->xmms_session); /* free the plugin data structure */ g_free(pd); } /* read plugin parameters */ void xmms_plugin_read_config(Control *control, xmlNodePtr node) { xmlChar *value; gint n; gboolean b; plugin_data *pd = (plugin_data *) control->data; g_return_if_fail(node!=NULL && node->children!=NULL); /* Read xml properties. All values out of range will be ignored. */ /* The default will be used then. */ node=node->children; /* get song text size */ value = xmlGetProp (node, (const xmlChar *) "textsize"); if (value) { n = atoi((char*) value); if ((n >= MIN_TITLE_SIZE) && (n <= MAX_TITLE_SIZE)) pd->titletextsize = n; } xmlFree(value); /* get scroll speed */ value = xmlGetProp (node, (const xmlChar *) "scroll_speed"); if (value) { n = atoi((char*) value); if ((n >= MIN_SCROLL_SPEED) && (n <= MAX_SCROLL_SPEED)) { pd->scroll_speed = n; pd->timer_reset = TRUE; } } xmlFree(value); /* get scroll step width */ value = xmlGetProp (node, (const xmlChar *) "scroll_step"); if (value) { n = atoi((char*) value); if ((n >= MIN_SCROLL_STEP) && (n <= MAX_SCROLL_STEP)) pd->scroll_step = n; } xmlFree(value); /* get scroll delay */ value = xmlGetProp (node, (const xmlChar *) "scroll_delay"); if (value) { n = atoi((char*) value); if ((n >= MIN_SCROLL_DELAY) && (n <= MAX_SCROLL_DELAY)) pd->scroll_delay = n; } xmlFree(value); pd->step_delay = pd->scroll_delay * pd->scroll_speed * pd->scroll_step; /* get xmms window visibility */ value = xmlGetProp (node, (const xmlChar *) "xmms_visible"); if (strcmp(value, "TRUE")) pd->xmmsvisible = TRUE; xmlFree(value); /* get visibility of scrolled song title*/ value = xmlGetProp (node, (const xmlChar *) "title_visible"); if (strcmp(value, "TRUE")) pd->show_scrolledtitle = TRUE; xmlFree(value); } /* save plugin parameters */ void xmms_plugin_write_config(Control *ctrl, xmlNodePtr parent) { xmlChar value[10]; plugin_data *pd=(plugin_data *)ctrl->data; xmlNodePtr node; g_return_if_fail(parent!=NULL); node = xmlNewTextChild (parent, NULL, (const xmlChar *)"XmmsControl", NULL); g_return_if_fail(node!=NULL); /* save title font size */ g_snprintf (value, 5, "%d", pd->titletextsize); xmlSetProp (node, "textsize", (const xmlChar *)value); /* save scroll speed */ g_snprintf (value, 5, "%d", pd->scroll_speed); xmlSetProp (node, "scroll_speed", (const xmlChar *)value); /* save scroll step width */ g_snprintf (value, 5, "%d", pd->scroll_step); xmlSetProp (node, "scroll_step", (const xmlChar *)value); /* save scroll delay */ g_snprintf (value, 5, "%d", pd->scroll_delay); xmlSetProp (node, "scroll_delay", (const xmlChar *)value); /* save xmms window visibility */ xmlSetProp (node, "xmms_visible", (pd->xmmsvisible) ? "TRUE" : "FALSE"); /* save visibility of scrolled sing title */ xmlSetProp (node, "title_visible", (pd->show_scrolledtitle) ? "TRUE" : "FALSE"); } /* generic function to add panel callbacks to the base widget */ static void xmms_plugin_attach_callback(Control *ctrl, const gchar *signal, GCallback cb, gpointer data) { g_signal_connect(ctrl->base, signal, cb, data); } /* callback to change the plugin size */ static void xmms_plugin_set_size(Control *ctrl, int size){ /* do the resize */ /* yeah...do it....or something */ } /* callback to change the font size */ static void set_font_size(GtkSpinButton *spin, gpointer data) { plugin_data *pd = (plugin_data*) data; PangoAttrSize *attr = (PangoAttrSize*) pd->labelattr; pd->titletextsize = gtk_spin_button_get_value_as_int(spin); if (pd->titletextsize < MIN_TITLE_SIZE) pd->titletextsize = 1; if (pd->titletextsize > MAX_TITLE_SIZE) pd->titletextsize = MAX_TITLE_SIZE; attr->size = pd->titletextsize * PANGO_SCALE; gtk_label_set_attributes(GTK_LABEL(pd->label), pd->labelattrlist); } /* callback to change the scroll speed */ static void set_scroll_speed(GtkSpinButton *spin, gpointer data) { plugin_data *pd = (plugin_data*) data; pd->scroll_speed = gtk_spin_button_get_value_as_int(spin); if (pd->scroll_speed < MIN_SCROLL_SPEED) pd->scroll_speed = MIN_SCROLL_SPEED; if (pd->scroll_speed > MAX_SCROLL_SPEED) pd->scroll_speed = MAX_SCROLL_SPEED; pd->timer_reset = TRUE; } /* callback to change the scroll step width */ static void set_scroll_step(GtkSpinButton *spin, gpointer data) { plugin_data *pd = (plugin_data*) data; gint s = gtk_spin_button_get_value_as_int(spin); if (s < MIN_SCROLL_STEP) s = MIN_SCROLL_STEP; if (s > MAX_SCROLL_STEP) s = MAX_SCROLL_STEP; pd->scroll_step = s; if (s == 0) pd->title_scroll_position = 0; } /* callback to change the scroll delay */ static void set_scroll_delay(GtkSpinButton *spin, gpointer data) { plugin_data *pd = (plugin_data*) data; gint d = gtk_spin_button_get_value_as_int(spin); if (d < MIN_SCROLL_DELAY) d = MIN_SCROLL_DELAY; if (d > MAX_SCROLL_DELAY) d = MAX_SCROLL_DELAY; pd->scroll_delay = d; pd->step_delay = d * pd->scroll_speed * pd->scroll_step; pd->title_scroll_position = 0; } /* add label to the left column of the options table */ static void add_label(GtkWidget *table, gchar *text, gint pos) { gint att_opts = GTK_SHRINK | GTK_EXPAND | GTK_FILL; GtkWidget *label = gtk_label_new(text); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach (GTK_TABLE(table), label, 0, 1, pos, pos+1, att_opts, att_opts, 0, 0); } /* add spin button to the right columns of the options table */ static void add_spin(GtkWidget *table, gint min, gint max, gint value, gpointer cb, gpointer data, gint pos) { gint att_opts = GTK_SHRINK/* | GTK_EXPAND | GTK_FILL*/; GtkWidget *spin = gtk_spin_button_new_with_range(min, max, 1.0); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), value); gtk_table_attach (GTK_TABLE(table), spin, 1, 2, pos, pos+1, att_opts, att_opts, 0, 0); g_signal_connect (G_OBJECT(spin), "value-changed", G_CALLBACK(cb), data); } /* add check button to the right columns of the options table */ static void add_spin(GtkWidget *parent, gpointer cb, gpointer data) { GtkWidget *check = gtk_check_button_new_with_label("Show scrolled song title"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check } /* options dialog */ static void xmms_plugin_create_options (Control *ctrl, GtkContainer *con, GtkWidget *done) { plugin_data *pd = (plugin_data*) ctrl->data; GtkWidget *vbox, *table, *label, *size, *speed, *step, *delay; gint att_opts = GTK_SHRINK | GTK_EXPAND | GTK_FILL; vbox = gtk_vbox_new (FALSE, 4); label = gtk_hseparator_new(); table = gtk_table_new (4, 2, FALSE); gtk_box_pack_start (GTK_BOX(vbox), label, DOEXPAND, DOFILL, PADDING); gtk_box_pack_start (GTK_BOX(vbox), table, DOEXPAND, DOFILL, PADDING); /* put labels into the left column of our table */ add_label(table, "Font Size", 0); add_label(table, "Scroll Speed", 1); add_label(table, "Scroll Stepwidth", 2); add_label(table, "Scroll Delay", 3); /* put spin buttons into the right column */ add_spin(table, MIN_TITLE_SIZE, MAX_TITLE_SIZE, pd->titletextsize, set_font_size, pd, 0); add_spin(table, MIN_SCROLL_SPEED, MAX_SCROLL_SPEED, pd->scroll_speed, set_scroll_speed, pd, 1); add_spin(table, MIN_SCROLL_STEP, MAX_SCROLL_STEP, pd->scroll_step, set_scroll_step, pd, 2); add_spin(table, MIN_SCROLL_DELAY, MAX_SCROLL_DELAY, pd->scroll_delay, set_scroll_delay, pd, 3); gtk_container_add (GTK_CONTAINER(con), vbox); gtk_widget_show_all(vbox); } /* initialization */ G_MODULE_EXPORT void xfce_control_class_init(ControlClass *cc){ /* these are required */ cc->name = "xmms_plugin"; cc->caption = _("XMMS Control"); cc->create_control = (CreateControlFunc) xmms_plugin_control_new; cc->free = xmms_plugin_free; cc->attach_callback = xmms_plugin_attach_callback; /* options */ cc->read_config = xmms_plugin_read_config; cc->write_config = xmms_plugin_write_config; cc->create_options = xmms_plugin_create_options; /* Don't use this function at all if you want xfce to * do the sizing. * Just define the set_size function to NULL, or rather, don't * set it to something else. */ cc->set_size = xmms_plugin_set_size; /* unused in the sample: * ->set_orientation * ->set_theme */ } /* required! defined in panel/plugins.h */ XFCE_PLUGIN_CHECK_INIT