simplify com_man() of command_util.sh
[paraslash.git] / krell.c
1 /*
2  * Copyright (C) 2004-2005 Andre Noll <maan@systemlinux.org>
3  *
4  *     This program is free software; you can redistribute it and/or modify
5  *     it under the terms of the GNU General Public License as published by
6  *     the Free Software Foundation; either version 2 of the License, or
7  *     (at your option) any later version.
8  *
9  *     This program is distributed in the hope that it will be useful,
10  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *     GNU General Public License for more details.
13  *
14  *     You should have received a copy of the GNU General Public License
15  *     along with this program; if not, write to the Free Software
16  *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
17  */
18
19
20 //#define PRINTF printf
21 #define PRINTF(a, ...)
22
23 #include <gkrellm2/gkrellm.h>
24 #include <utime.h>
25 #include <dirent.h>
26 #include <errno.h>
27 #include <stdio.h>
28 #include <sys/time.h>
29 #include <sys/wait.h>
30
31 static void create_para_ctrl(GtkWidget *, gint);
32 static void update_para_ctrl(void);
33 static void create_tab(GtkWidget *);
34 static void apply_config(void);
35 static void load_config(gchar *);
36 static void save_config(FILE *);
37
38 static GkrellmMonitor monitor = {
39         "Parakrell",            /* Name, for config tab. */
40         0,                      /* Id,  0 if a plugin */
41         create_para_ctrl,       /* The create function */
42         update_para_ctrl,       /* The update function */
43         create_tab,             /* The config tab create function */
44         apply_config,           /* Apply the config function */
45         save_config,            /* Save user config */
46         load_config,            /* Load user config */
47         "para_krell",           /* config keyword */
48         NULL,                   /* Undefined 2  */
49         NULL,                   /* Undefined 1  */
50         NULL,                   /* Undefined 0  */
51         MON_APM,                /* Insert plugin before this monitor */
52         NULL,                   /* Handle if a plugin, filled in by GKrellM */
53         NULL                    /* path if a plugin, filled in by GKrellM */
54 };
55
56 typedef struct {
57         GkrellmPiximage *image;
58         GkrellmDecalbutton *button;
59         gint x,y,w,h;
60         double x_scale,y_scale;
61 } ControlButton;
62
63 static ControlButton prev_button = {
64         .image = NULL,
65         .button = NULL,
66         .x = 10,
67         .y = 10,
68         .w = 50,
69         .h = 50,
70         .x_scale = 1,
71         .y_scale = 1,
72 };
73
74 GkrellmPiximage *piximage;
75 GkrellmPanel *panel;
76 GtkWidget *fileread_vbox;
77 GdkPixbuf *pixbuf;
78 gint song_change_input_id;
79 FILE *song_change_fd;
80 GIOChannel *song_change_channel;
81
82 static struct timeval sc_open_time;
83
84 static gchar *info_text =
85         "Parakrell displays an image corresponding to the soundfile\n"
86         "currently played by paraslash.\n\n"
87
88         "The plugin's panel is divided in 9 small squares, like      \n"
89         "the numpad on a PC keyboard.  For each square there is an   \n"
90         "associated button and a number between 1 and 9.\n           \n"
91
92         "Each button is bound to three different commands for left,  \n"
93         "middle and right mouse button.  Middle and right button are \n"
94         "reserved for setting volume and jumping around in the song, \n"
95         "respectively. Left button works as follows:\n               \n"
96
97         "7  8  9                       7: slider, 8: sdl_gui, 9: next \n"
98         "4  5  6                       4: ps,     5: play,    6: dbadm \n"
99         "1  2  3                       1: stop,   2: gui,     3: pause\n"
100
101         "\n\nAuthor:\n"
102         "Andre Noll <maan@systemlinux.org>\n"
103         "Copyright (C) 2004-2005\n"
104         "Distributed under the GNU General Public License.\n";
105
106 #define MAXLINE 255
107
108 static gboolean launch_cmd(char *cmd)
109 {
110
111         gchar **argv;
112         GError *err = NULL;
113         gboolean res;
114
115         PRINTF("%s: \n", __func__);
116         if (!cmd || *cmd == '\0')
117                 return -1;
118
119         g_shell_parse_argv(cmd, NULL, &argv, NULL);
120         res = g_spawn_async(
121                 NULL,
122                 argv,
123                 NULL,
124                 G_SPAWN_SEARCH_PATH | G_SPAWN_STDERR_TO_DEV_NULL,
125                 NULL,
126                 NULL,
127                 NULL,
128                 &err
129         );
130         if (!res && err) {
131                 gkrellm_message_dialog(NULL, err->message);
132                 g_error_free(err);
133         }
134         g_strfreev(argv);
135         return res;
136 }
137
138 static gboolean cb_in_button(GkrellmDecalbutton *b,
139         GdkEventButton *ev, ControlButton *cbut)
140 {
141         gint x, y, area, width = gkrellm_chart_width();
142         x = (int) (3 * ev->x / width);
143         y = (int) (3 - 3 * ev->y / width);
144         area = 3 * y + x + 1;
145         char buf[MAXLINE];
146
147         PRINTF("%s: button %i pressed on area %i\n", __func__,
148                 ev->button, area);
149         if (ev->button == 1) {
150                 switch (area) {
151                 case 1:
152                         launch_cmd("para_client stop");
153                         return 0;
154                 case 2:
155                         launch_cmd("xterm -e para_gui -a");
156                         return 0;
157                 case 3:
158                         launch_cmd("para_client pause");
159                         return 0;
160                 case 4:
161                         launch_cmd("para_client ps");
162                         return 0;
163                 case 5:
164                         launch_cmd("para_client play");
165                         return 0;
166                 case 6:
167                         launch_cmd("xterm -e para_dbadm");
168                         return 0;
169                 case 7:
170                         launch_cmd("para_slider");
171                         return 0;
172                 case 8:
173                         launch_cmd("para_sdl_gui -f");
174                         return 0;
175                 case 9:
176                         launch_cmd("para_client next");
177                         return 0;
178                 }
179                 return 0;
180         }
181         sprintf(buf, "%s %i", ev->button == 2? "aumix -v" : "para_client jmp",
182                 area * 10);
183         return launch_cmd(buf);
184 }
185
186 static void make_button(ControlButton *cbut, gint fn_id)
187 {
188         PRINTF("%s: gkrellm_make_scaled_button\n", __func__);
189         cbut->button = gkrellm_make_scaled_button(
190                 panel,
191                 cbut->image,
192                 NULL,
193                 GINT_TO_POINTER(fn_id),
194                 FALSE,
195                 FALSE,
196                 2,
197                 0,
198                 1,
199                 cbut->x,
200                 cbut->y,
201                 cbut->w,
202                 cbut->h
203         );
204         PRINTF("%s: making botton\n", __func__);
205         gkrellm_set_in_button_callback(cbut->button, cb_in_button, cbut);
206 }
207
208
209 static void load_img(void)
210 {
211         gint width = gkrellm_chart_width();
212         gint out = 0, ret;
213         FILE *pipe = NULL;
214         char buf[MAXLINE];
215         size_t num_read = 0;
216         gchar *filename = gkrellm_make_data_file_name("para", "pic.jpg");
217
218         PRINTF("%s: Opening %s\n", __func__, filename);
219         if ((out = creat(filename, S_IRUSR | S_IWUSR)) < 0) {
220                 perror("open");
221                 goto out;
222         }
223         pipe = popen("para_client pic", "r");
224         if (!pipe)
225                 goto out;
226         while ((ret = read(fileno(pipe), buf, sizeof(buf) - 1)) > 0) {
227                 if (write(out, buf, ret) < 0) {
228                         perror("Write");
229                         goto out;
230                 }
231                 num_read += ret;
232         }
233         if (ret < 0) {
234                 PRINTF("%s: Read Error\n", __func__);
235                 goto out;
236         }
237         PRINTF("%s: new pic created (%i bytes)\n", __func__, num_read);
238         if (num_read < 500)
239                 goto out;
240
241         if (piximage) {
242                 gkrellm_destroy_piximage(piximage);
243                 g_free(pixbuf);
244         }
245         PRINTF("%s: creating new piximage\n", __func__);
246         piximage = gkrellm_piximage_new_from_file(filename);
247         if (!piximage) {
248                 PRINTF("%s: can not load image\n", __func__);
249                 goto out;
250         }
251         pixbuf = gkrellm_scale_piximage_to_pixbuf(piximage, width, width);
252 out:
253         g_free(filename);
254         if (pipe)
255                 pclose(pipe);
256         if (out)
257                 close(out);
258 }
259
260 static void create_tab(GtkWidget *tab_vbox)
261 {
262         GtkTextBuffer *textbuf;
263         GtkWidget *text;
264         GtkWidget *scrolled, *vbox = tab_vbox;
265
266         PRINTF("%s: \n", __func__);
267
268         scrolled = gtk_scrolled_window_new(NULL, NULL);
269         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
270                                        GTK_POLICY_AUTOMATIC,
271                                        GTK_POLICY_AUTOMATIC);
272         textbuf = gtk_text_buffer_new(NULL);
273         gtk_text_buffer_set_text(textbuf, info_text, -1);
274         text = gtk_text_view_new_with_buffer(textbuf);
275         gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE);
276         gtk_container_add(GTK_CONTAINER(scrolled), text);
277         gtk_box_pack_start(GTK_BOX(vbox), scrolled, TRUE, TRUE, 0);
278 }
279
280 static gboolean song_change(GIOChannel *channel, GIOCondition condition,
281                 gpointer panel)
282 {
283         char *str_return;
284         gsize length;
285
286         PRINTF("%s: input condition %i "
287                 "(song_change channel fd = %i)\n", __func__, condition,
288                 g_io_channel_unix_get_fd(song_change_channel));
289         if (!song_change_fd) {
290                 PRINTF("%s: no song_change_fd\n", __func__);
291                 goto err_out;
292         }
293         if (!(condition & (G_IO_IN | G_IO_PRI))) {
294                 PRINTF("%s: song change pipe died\n", __func__);
295                 song_change_fd = NULL;
296                 wait(NULL);
297                 return TRUE;
298                 goto err_out;
299         }
300         if (!channel->is_readable) {
301                 PRINTF("%s: fd not readable\n", __func__);
302                 goto err_out;
303         }
304         PRINTF("%s: reading data\n", __func__);
305         if (g_io_channel_read_line(channel, &str_return,
306                         &length, NULL, NULL) == G_IO_STATUS_NORMAL) {
307                 PRINTF("%s: next song: %s", __func__, str_return);
308                 g_free(str_return);
309                 if (channel != song_change_channel)
310                         goto err_out;
311                 load_img();
312                 return TRUE;
313         }
314 err_out:
315         g_io_channel_unref(channel);
316         g_io_channel_shutdown(channel, TRUE, NULL);
317         return FALSE;
318 }
319
320 static void create_song_change(void)
321 {
322         if (song_change_fd)
323                 return;
324         gettimeofday(&sc_open_time, NULL);
325         PRINTF("%s: para_client sc\n", __func__);
326         song_change_fd = popen("para_client sc", "r");
327         if (!song_change_fd) {
328                 PRINTF("%s: para_client sc failed\n", __func__);
329                 return;
330         }
331         song_change_channel = g_io_channel_unix_new(fileno(song_change_fd));
332         g_io_channel_set_close_on_unref(song_change_channel, TRUE);
333         g_io_add_watch(song_change_channel,
334                 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
335                 &song_change, panel);
336 }
337
338 static void update_para_ctrl(void)
339 {
340         GdkDrawable  *drawable = panel->drawing_area->window;
341         gint width = gkrellm_chart_width();
342
343         if (!drawable)
344                 PRINTF("%s: No drawable\n", __func__);
345         else
346                 gkrellm_paste_pixbuf(pixbuf, drawable, 0, 0, width, width);
347         if (!song_change_fd) {
348                 struct timeval now;
349                 PRINTF("%s: no song_change_fd\n", __func__);
350
351                 gettimeofday(&now, NULL);
352                 if (now.tv_sec > sc_open_time.tv_sec + 5)
353                         create_song_change();
354         }
355 }
356
357 static void destroy_panel(void)
358 {
359         PRINTF("%s: \n", __func__);
360         if (!panel) 
361                 return;
362         PRINTF("%s: destroying panel\n", __func__);
363         gkrellm_panel_destroy(panel);
364         panel = NULL;
365 }
366
367 #if 0
368 static void destroy_song_change(void)
369 {
370         PRINTF("%s: \n", __func__);
371         if (!song_change_fd)
372                 return;
373 }
374 #endif
375 static void destroy_all(void)
376 {
377 //      destroy_song_change();
378         destroy_panel();
379 }
380
381 static void create_para_ctrl(GtkWidget *vbox, gint first_create)
382 {
383         gint style_id = gkrellm_lookup_meter_style_id(UPTIME_STYLE_NAME);
384         GkrellmStyle *style = gkrellm_meter_style(style_id);
385         gint width = gkrellm_chart_width();
386
387         destroy_all();
388         create_song_change();
389         panel = gkrellm_panel_new0();
390         gkrellm_panel_configure(panel, NULL, style);
391         gkrellm_panel_configure_set_height(panel, width);
392         PRINTF("%s: creating panel\n", __func__);
393         gkrellm_panel_create(vbox, &monitor, panel);
394         make_button(&prev_button, 1);
395 }
396
397 static void apply_config(void)
398 {
399         PRINTF("%s: \n", __func__);
400 }
401
402 static void load_config(gchar * arg)
403 {
404         PRINTF("%s: \n", __func__);
405
406 }
407
408 static void save_config(FILE * f)
409 {
410         PRINTF("%s: \n", __func__);
411 }
412
413 GkrellmMonitor *gkrellm_init_plugin(void)
414 {
415         return &monitor;
416 }