fix dccp sender/receiver
[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 }