Mercurial > geeqie.yaz
comparison src/remote.c @ 1554:a96a20c7feb1
improved remote protocol to allow bidirectional communication
author | nadvornik |
---|---|
date | Mon, 20 Apr 2009 19:44:50 +0000 |
parents | 24a12aa0cb54 |
children | 3840882253fe |
comparison
equal
deleted
inserted
replaced
1553:626adbb26387 | 1554:a96a20c7feb1 |
---|---|
65 | 65 |
66 rc = client->rc; | 66 rc = client->rc; |
67 | 67 |
68 if (condition & G_IO_IN) | 68 if (condition & G_IO_IN) |
69 { | 69 { |
70 GList *queue = NULL; | |
71 GList *work; | |
72 gchar *buffer = NULL; | 70 gchar *buffer = NULL; |
73 GError *error = NULL; | 71 GError *error = NULL; |
74 gsize termpos; | 72 gsize termpos; |
75 | 73 |
76 while ((status = g_io_channel_read_line(source, &buffer, NULL, &termpos, &error)) == G_IO_STATUS_NORMAL) | 74 while ((status = g_io_channel_read_line(source, &buffer, NULL, &termpos, &error)) == G_IO_STATUS_NORMAL) |
79 { | 77 { |
80 buffer[termpos] = '\0'; | 78 buffer[termpos] = '\0'; |
81 | 79 |
82 if (strlen(buffer) > 0) | 80 if (strlen(buffer) > 0) |
83 { | 81 { |
84 queue = g_list_append(queue, buffer); | 82 if (rc->read_func) rc->read_func(rc, buffer, source, rc->read_data); |
83 g_io_channel_write_chars(source, "\n", -1, NULL, NULL); /* empty line finishes the command */ | |
84 g_io_channel_flush(source, NULL); | |
85 } | 85 } |
86 else | 86 g_free(buffer); |
87 { | |
88 g_free(buffer); | |
89 } | |
90 | 87 |
91 buffer = NULL; | 88 buffer = NULL; |
92 } | 89 } |
93 } | 90 } |
94 | 91 |
95 if (error) | 92 if (error) |
96 { | 93 { |
97 log_printf("error reading socket: %s\n", error->message); | 94 log_printf("error reading socket: %s\n", error->message); |
98 g_error_free(error); | 95 g_error_free(error); |
99 } | 96 } |
100 | |
101 work = queue; | |
102 while (work) | |
103 { | |
104 gchar *command = work->data; | |
105 work = work->next; | |
106 | |
107 if (rc->read_func) rc->read_func(rc, command, rc->read_data); | |
108 g_free(command); | |
109 } | |
110 | |
111 g_list_free(queue); | |
112 } | 97 } |
113 | 98 |
114 if (condition & G_IO_HUP || status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR) | 99 if (condition & G_IO_HUP || status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR) |
115 { | 100 { |
116 rc->clients = g_list_remove(rc->clients, client); | 101 rc->clients = g_list_remove(rc->clients, client); |
277 rc = g_new0(RemoteConnection, 1); | 262 rc = g_new0(RemoteConnection, 1); |
278 rc->server = FALSE; | 263 rc->server = FALSE; |
279 rc->fd = fd; | 264 rc->fd = fd; |
280 rc->path = g_strdup(path); | 265 rc->path = g_strdup(path); |
281 | 266 |
282 /* this might fix the freezes on freebsd, solaris, etc. - completely untested */ | |
283 remote_client_send(rc, "\n"); | |
284 | |
285 return rc; | 267 return rc; |
286 } | 268 } |
287 | 269 |
288 static sig_atomic_t sigpipe_occured = FALSE; | 270 static sig_atomic_t sigpipe_occured = FALSE; |
289 | 271 |
294 | 276 |
295 static gboolean remote_client_send(RemoteConnection *rc, const gchar *text) | 277 static gboolean remote_client_send(RemoteConnection *rc, const gchar *text) |
296 { | 278 { |
297 struct sigaction new_action, old_action; | 279 struct sigaction new_action, old_action; |
298 gboolean ret = FALSE; | 280 gboolean ret = FALSE; |
281 GError *error = NULL; | |
282 GIOChannel *channel; | |
299 | 283 |
300 if (!rc || rc->server) return FALSE; | 284 if (!rc || rc->server) return FALSE; |
301 if (!text) return TRUE; | 285 if (!text) return TRUE; |
302 | 286 |
303 sigpipe_occured = FALSE; | 287 sigpipe_occured = FALSE; |
307 new_action.sa_flags = 0; | 291 new_action.sa_flags = 0; |
308 | 292 |
309 /* setup our signal handler */ | 293 /* setup our signal handler */ |
310 sigaction(SIGPIPE, &new_action, &old_action); | 294 sigaction(SIGPIPE, &new_action, &old_action); |
311 | 295 |
312 if (write(rc->fd, text, strlen(text)) == -1 || | 296 channel = g_io_channel_unix_new(rc->fd); |
313 write(rc->fd, "\n", 1) == -1) | 297 |
314 { | 298 g_io_channel_write_chars(channel, text, -1, NULL, &error); |
315 if (sigpipe_occured) | 299 g_io_channel_write_chars(channel, "\n", -1, NULL, &error); |
316 { | 300 g_io_channel_flush(channel, &error); |
317 log_printf("SIGPIPE writing to socket: %s\n", rc->path); | 301 |
318 } | 302 if (error) |
319 else | 303 { |
320 { | 304 log_printf("error reading socket: %s\n", error->message); |
321 log_printf("error writing to socket: %s\n", strerror(errno)); | 305 g_error_free(error); |
322 } | |
323 ret = FALSE;; | 306 ret = FALSE;; |
324 } | 307 } |
325 else | 308 else |
326 { | 309 { |
327 ret = TRUE; | 310 ret = TRUE; |
328 } | 311 } |
312 | |
313 if (ret) | |
314 { | |
315 gchar *buffer = NULL; | |
316 gsize termpos; | |
317 while (g_io_channel_read_line(channel, &buffer, NULL, &termpos, &error) == G_IO_STATUS_NORMAL) | |
318 { | |
319 if (buffer) | |
320 { | |
321 if (buffer[0] == '\n') /* empty line finishes the command */ | |
322 { | |
323 g_free(buffer); | |
324 break; | |
325 } | |
326 buffer[termpos] = '\0'; | |
327 printf("%s\n", buffer); | |
328 g_free(buffer); | |
329 buffer = NULL; | |
330 } | |
331 } | |
332 | |
333 if (error) | |
334 { | |
335 log_printf("error reading socket: %s\n", error->message); | |
336 g_error_free(error); | |
337 ret = FALSE; | |
338 } | |
339 } | |
340 | |
329 | 341 |
330 /* restore the original signal handler */ | 342 /* restore the original signal handler */ |
331 sigaction(SIGPIPE, &old_action, NULL); | 343 sigaction(SIGPIPE, &old_action, NULL); |
332 | 344 g_io_channel_unref(channel); |
333 return ret; | 345 return ret; |
334 } | 346 } |
335 | 347 |
336 void remote_close(RemoteConnection *rc) | 348 void remote_close(RemoteConnection *rc) |
337 { | 349 { |
358 *----------------------------------------------------------------------------- | 370 *----------------------------------------------------------------------------- |
359 * remote functions | 371 * remote functions |
360 *----------------------------------------------------------------------------- | 372 *----------------------------------------------------------------------------- |
361 */ | 373 */ |
362 | 374 |
363 static void gr_image_next(const gchar *text, gpointer data) | 375 static void gr_image_next(const gchar *text, GIOChannel *channel, gpointer data) |
364 { | 376 { |
365 layout_image_next(NULL); | 377 layout_image_next(NULL); |
366 } | 378 } |
367 | 379 |
368 static void gr_image_prev(const gchar *text, gpointer data) | 380 static void gr_image_prev(const gchar *text, GIOChannel *channel, gpointer data) |
369 { | 381 { |
370 layout_image_prev(NULL); | 382 layout_image_prev(NULL); |
371 } | 383 } |
372 | 384 |
373 static void gr_image_first(const gchar *text, gpointer data) | 385 static void gr_image_first(const gchar *text, GIOChannel *channel, gpointer data) |
374 { | 386 { |
375 layout_image_first(NULL); | 387 layout_image_first(NULL); |
376 } | 388 } |
377 | 389 |
378 static void gr_image_last(const gchar *text, gpointer data) | 390 static void gr_image_last(const gchar *text, GIOChannel *channel, gpointer data) |
379 { | 391 { |
380 layout_image_last(NULL); | 392 layout_image_last(NULL); |
381 } | 393 } |
382 | 394 |
383 static void gr_fullscreen_toggle(const gchar *text, gpointer data) | 395 static void gr_fullscreen_toggle(const gchar *text, GIOChannel *channel, gpointer data) |
384 { | 396 { |
385 layout_image_full_screen_toggle(NULL); | 397 layout_image_full_screen_toggle(NULL); |
386 } | 398 } |
387 | 399 |
388 static void gr_fullscreen_start(const gchar *text, gpointer data) | 400 static void gr_fullscreen_start(const gchar *text, GIOChannel *channel, gpointer data) |
389 { | 401 { |
390 layout_image_full_screen_start(NULL); | 402 layout_image_full_screen_start(NULL); |
391 } | 403 } |
392 | 404 |
393 static void gr_fullscreen_stop(const gchar *text, gpointer data) | 405 static void gr_fullscreen_stop(const gchar *text, GIOChannel *channel, gpointer data) |
394 { | 406 { |
395 layout_image_full_screen_stop(NULL); | 407 layout_image_full_screen_stop(NULL); |
396 } | 408 } |
397 | 409 |
398 static void gr_slideshow_start_rec(const gchar *text, gpointer data) | 410 static void gr_slideshow_start_rec(const gchar *text, GIOChannel *channel, gpointer data) |
399 { | 411 { |
400 GList *list; | 412 GList *list; |
401 FileData *dir_fd = file_data_new_simple(text); | 413 FileData *dir_fd = file_data_new_simple(text); |
402 list = filelist_recursive(dir_fd); | 414 list = filelist_recursive(dir_fd); |
403 file_data_unref(dir_fd); | 415 file_data_unref(dir_fd); |
405 //printf("length: %d\n", g_list_length(list)); | 417 //printf("length: %d\n", g_list_length(list)); |
406 layout_image_slideshow_stop(NULL); | 418 layout_image_slideshow_stop(NULL); |
407 layout_image_slideshow_start_from_list(NULL, list); | 419 layout_image_slideshow_start_from_list(NULL, list); |
408 } | 420 } |
409 | 421 |
410 static void gr_slideshow_toggle(const gchar *text, gpointer data) | 422 static void gr_slideshow_toggle(const gchar *text, GIOChannel *channel, gpointer data) |
411 { | 423 { |
412 layout_image_slideshow_toggle(NULL); | 424 layout_image_slideshow_toggle(NULL); |
413 } | 425 } |
414 | 426 |
415 static void gr_slideshow_start(const gchar *text, gpointer data) | 427 static void gr_slideshow_start(const gchar *text, GIOChannel *channel, gpointer data) |
416 { | 428 { |
417 layout_image_slideshow_start(NULL); | 429 layout_image_slideshow_start(NULL); |
418 } | 430 } |
419 | 431 |
420 static void gr_slideshow_stop(const gchar *text, gpointer data) | 432 static void gr_slideshow_stop(const gchar *text, GIOChannel *channel, gpointer data) |
421 { | 433 { |
422 layout_image_slideshow_stop(NULL); | 434 layout_image_slideshow_stop(NULL); |
423 } | 435 } |
424 | 436 |
425 static void gr_slideshow_delay(const gchar *text, gpointer data) | 437 static void gr_slideshow_delay(const gchar *text, GIOChannel *channel, gpointer data) |
426 { | 438 { |
427 gdouble n; | 439 gdouble n; |
428 | 440 |
429 n = g_ascii_strtod(text, NULL); | 441 n = g_ascii_strtod(text, NULL); |
430 if (n < SLIDESHOW_MIN_SECONDS || n > SLIDESHOW_MAX_SECONDS) | 442 if (n < SLIDESHOW_MIN_SECONDS || n > SLIDESHOW_MAX_SECONDS) |
434 return; | 446 return; |
435 } | 447 } |
436 options->slideshow.delay = (gint)(n * 10.0 + 0.01); | 448 options->slideshow.delay = (gint)(n * 10.0 + 0.01); |
437 } | 449 } |
438 | 450 |
439 static void gr_tools_show(const gchar *text, gpointer data) | 451 static void gr_tools_show(const gchar *text, GIOChannel *channel, gpointer data) |
440 { | 452 { |
441 gboolean popped; | 453 gboolean popped; |
442 gboolean hidden; | 454 gboolean hidden; |
443 | 455 |
444 if (layout_tools_float_get(NULL, &popped, &hidden) && hidden) | 456 if (layout_tools_float_get(NULL, &popped, &hidden) && hidden) |
445 { | 457 { |
446 layout_tools_float_set(NULL, popped, FALSE); | 458 layout_tools_float_set(NULL, popped, FALSE); |
447 } | 459 } |
448 } | 460 } |
449 | 461 |
450 static void gr_tools_hide(const gchar *text, gpointer data) | 462 static void gr_tools_hide(const gchar *text, GIOChannel *channel, gpointer data) |
451 { | 463 { |
452 gboolean popped; | 464 gboolean popped; |
453 gboolean hidden; | 465 gboolean hidden; |
454 | 466 |
455 if (layout_tools_float_get(NULL, &popped, &hidden) && !hidden) | 467 if (layout_tools_float_get(NULL, &popped, &hidden) && !hidden) |
463 exit_program(); | 475 exit_program(); |
464 | 476 |
465 return FALSE; | 477 return FALSE; |
466 } | 478 } |
467 | 479 |
468 static void gr_quit(const gchar *text, gpointer data) | 480 static void gr_quit(const gchar *text, GIOChannel *channel, gpointer data) |
469 { | 481 { |
470 /* schedule exit when idle, if done from within a | 482 /* schedule exit when idle, if done from within a |
471 * remote handler remote_close will crash | 483 * remote handler remote_close will crash |
472 */ | 484 */ |
473 g_idle_add(gr_quit_idle_cb, NULL); | 485 g_idle_add(gr_quit_idle_cb, NULL); |
474 } | 486 } |
475 | 487 |
476 static void gr_file_load(const gchar *text, gpointer data) | 488 static void gr_file_load(const gchar *text, GIOChannel *channel, gpointer data) |
477 { | 489 { |
478 gchar *filename = expand_tilde(text); | 490 gchar *filename = expand_tilde(text); |
479 | 491 |
480 if (isfile(filename)) | 492 if (isfile(filename)) |
481 { | 493 { |
498 } | 510 } |
499 | 511 |
500 g_free(filename); | 512 g_free(filename); |
501 } | 513 } |
502 | 514 |
503 static void gr_config_load(const gchar *text, gpointer data) | 515 static void gr_config_load(const gchar *text, GIOChannel *channel, gpointer data) |
504 { | 516 { |
505 gchar *filename = expand_tilde(text); | 517 gchar *filename = expand_tilde(text); |
506 | 518 |
507 if (isfile(filename)) | 519 if (isfile(filename)) |
508 { | 520 { |
514 } | 526 } |
515 | 527 |
516 g_free(filename); | 528 g_free(filename); |
517 } | 529 } |
518 | 530 |
519 static void gr_file_view(const gchar *text, gpointer data) | 531 static void gr_file_view(const gchar *text, GIOChannel *channel, gpointer data) |
520 { | 532 { |
521 gchar *filename = expand_tilde(text); | 533 gchar *filename = expand_tilde(text); |
522 | 534 |
523 view_window_new(file_data_new_simple(filename)); | 535 view_window_new(file_data_new_simple(filename)); |
524 g_free(filename); | 536 g_free(filename); |
525 } | 537 } |
526 | 538 |
527 static void gr_list_clear(const gchar *text, gpointer data) | 539 static void gr_list_clear(const gchar *text, GIOChannel *channel, gpointer data) |
528 { | 540 { |
529 RemoteData *remote_data = data; | 541 RemoteData *remote_data = data; |
530 | 542 |
531 if (remote_data->command_collection) | 543 if (remote_data->command_collection) |
532 { | 544 { |
533 collection_unref(remote_data->command_collection); | 545 collection_unref(remote_data->command_collection); |
534 remote_data->command_collection = NULL; | 546 remote_data->command_collection = NULL; |
535 } | 547 } |
536 } | 548 } |
537 | 549 |
538 static void gr_list_add(const gchar *text, gpointer data) | 550 static void gr_list_add(const gchar *text, GIOChannel *channel, gpointer data) |
539 { | 551 { |
540 RemoteData *remote_data = data; | 552 RemoteData *remote_data = data; |
541 gboolean new = TRUE; | 553 gboolean new = TRUE; |
542 | 554 |
543 if (!remote_data->command_collection) | 555 if (!remote_data->command_collection) |
563 layout_image_set_collection(NULL, remote_data->command_collection, | 575 layout_image_set_collection(NULL, remote_data->command_collection, |
564 collection_get_first(remote_data->command_collection)); | 576 collection_get_first(remote_data->command_collection)); |
565 } | 577 } |
566 } | 578 } |
567 | 579 |
568 static void gr_raise(const gchar *text, gpointer data) | 580 static void gr_raise(const gchar *text, GIOChannel *channel, gpointer data) |
569 { | 581 { |
570 LayoutWindow *lw = NULL; | 582 LayoutWindow *lw = NULL; |
571 | 583 |
572 if (layout_valid(&lw)) | 584 if (layout_valid(&lw)) |
573 { | 585 { |
577 | 589 |
578 typedef struct _RemoteCommandEntry RemoteCommandEntry; | 590 typedef struct _RemoteCommandEntry RemoteCommandEntry; |
579 struct _RemoteCommandEntry { | 591 struct _RemoteCommandEntry { |
580 gchar *opt_s; | 592 gchar *opt_s; |
581 gchar *opt_l; | 593 gchar *opt_l; |
582 void (*func)(const gchar *text, gpointer data); | 594 void (*func)(const gchar *text, GIOChannel *channel, gpointer data); |
583 gboolean needs_extra; | 595 gboolean needs_extra; |
584 gboolean prefer_command_line; | 596 gboolean prefer_command_line; |
585 gchar *description; | 597 gchar *description; |
586 }; | 598 }; |
587 | 599 |
648 } | 660 } |
649 | 661 |
650 return NULL; | 662 return NULL; |
651 } | 663 } |
652 | 664 |
653 static void remote_cb(RemoteConnection *rc, const gchar *text, gpointer data) | 665 static void remote_cb(RemoteConnection *rc, const gchar *text, GIOChannel *channel, gpointer data) |
654 { | 666 { |
655 RemoteCommandEntry *entry; | 667 RemoteCommandEntry *entry; |
656 const gchar *offset; | 668 const gchar *offset; |
657 | 669 |
658 entry = remote_command_find(text, &offset); | 670 entry = remote_command_find(text, &offset); |
659 if (entry && entry->func) | 671 if (entry && entry->func) |
660 { | 672 { |
661 entry->func(offset, data); | 673 entry->func(offset, channel, data); |
662 } | 674 } |
663 else | 675 else |
664 { | 676 { |
665 log_printf("unknown remote command:%s\n", text); | 677 log_printf("unknown remote command:%s\n", text); |
666 } | 678 } |