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