4 * Copyright (C) 2009 by ProFUSION embedded systems
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or (at your
9 * option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
21 * @author Rafael Antognolli <antognolli@profusion.mobi>
33 #include <Ecore_Getopt.h>
37 #include "ethumbd_private.h"
43 #define MAX_ID 2000000
45 #define DBG(...) EINA_LOG_DBG(__VA_ARGS__)
46 #define INF(...) EINA_LOG_INFO(__VA_ARGS__)
47 #define WRN(...) EINA_LOG_WARN(__VA_ARGS__)
48 #define ERR(...) EINA_LOG_ERR(__VA_ARGS__)
50 static const char _ethumb_dbus_bus_name[] = "org.enlightenment.Ethumb";
51 static const char _ethumb_dbus_interface[] = "org.enlightenment.Ethumb";
52 static const char _ethumb_dbus_objects_interface[] = "org.enlightenment.Ethumb.objects";
53 static const char _ethumb_dbus_path[] = "/org/enlightenment/Ethumb";
54 static const char fdo_interface[] = "org.freedesktop.DBus";
55 static const char fdo_bus_name[] = "org.freedesktop.DBus";
56 static const char fdo_path[] = "/org/freedesktop/DBus";
67 Eina_Bool quality : 1;
68 Eina_Bool compress : 1;
69 Eina_Bool directory : 1;
70 Eina_Bool category : 1;
72 Eina_Bool video_time : 1;
73 Eina_Bool video_start : 1;
74 Eina_Bool video_interval : 1;
75 Eina_Bool video_ntimes : 1;
76 Eina_Bool video_fps : 1;
77 Eina_Bool document_page : 1;
86 const char *directory;
88 const char *theme_file;
99 struct _Ethumb_Request
102 const char *file, *key;
103 const char *thumb, *thumb_key;
104 struct _Ethumb_Setup setup;
107 struct _Ethumb_Object
117 E_DBus_Object *dbus_obj;
127 struct _Ethumb_Object *table;
133 E_DBus_Connection *conn;
134 E_DBus_Signal_Handler *name_owner_changed_handler;
135 E_DBus_Interface *eiface, *objects_iface;
136 E_DBus_Object *dbus_obj;
138 struct _Ethumb_Request *processing;
139 struct _Ethumb_Queue queue;
142 Ecore_Fd_Handler *fd_handler;
144 Ecore_Timer *timeout_timer;
147 struct _Ethumb_Object_Data
153 struct _Ethumb_DBus_Method_Table
156 const char *signature;
158 E_DBus_Method_Cb function;
161 struct _Ethumb_DBus_Signal_Table
164 const char *signature;
167 const Ecore_Getopt optdesc = {
171 "(C) 2009 - ProFUSION embedded systems",
172 "LGPL v3 - GNU Lesser General Public License",
175 "ethumbd uses the Ethumb library to create thumbnails for any "
176 "program that requests it (now just by dbus).\n",
179 ECORE_GETOPT_STORE_DOUBLE
180 ('t', "timeout", "finish ethumbd after <timeout> seconds of no activity."),
181 ECORE_GETOPT_LICENSE('L', "license"),
182 ECORE_GETOPT_COPYRIGHT('C', "copyright"),
183 ECORE_GETOPT_VERSION('V', "version"),
184 ECORE_GETOPT_HELP('h', "help"),
185 ECORE_GETOPT_SENTINEL
189 static void _ethumb_dbus_generated_signal(struct _Ethumbd *ed, int *id, const char *thumb_path, const char *thumb_key, Eina_Bool success);
192 _ethumbd_timeout_cb(void *data)
194 struct _Ethumbd *ed = data;
196 ecore_main_loop_quit();
197 ed->timeout_timer = NULL;
203 _ethumbd_timeout_start(struct _Ethumbd *ed)
208 if (!ed->timeout_timer)
209 ed->timeout_timer = ecore_timer_add(ed->timeout, _ethumbd_timeout_cb, ed);
213 _ethumbd_timeout_stop(struct _Ethumbd *ed)
215 if (!ed->timeout_timer)
218 ecore_timer_del(ed->timeout_timer);
219 ed->timeout_timer = NULL;
223 _ethumb_dbus_check_id(struct _Ethumb_Object *eobject, int id)
225 if (id < 0 || id > MAX_ID)
228 if (eobject->min_id < eobject->max_id)
229 return id < eobject->min_id || id > eobject->max_id;
230 else if (eobject->min_id > eobject->max_id)
231 return id < eobject->min_id && id > eobject->max_id;
233 return id != eobject->max_id;
237 _ethumb_dbus_inc_max_id(struct _Ethumb_Object *eobject, int id)
239 if (eobject->min_id < 0 && eobject->max_id < 0)
240 eobject->min_id = id;
242 eobject->max_id = id;
246 _ethumb_dbus_inc_min_id(struct _Ethumb_Object *eobject)
253 struct _Ethumb_Request *request = l->data;
254 if (request->id >= 0)
256 eobject->min_id = request->id;
265 eobject->min_id = -1;
266 eobject->max_id = -1;
271 _ethumbd_read_safe(int fd, void *buf, ssize_t size)
283 r = read(fd, p, todo);
293 if (errno == EINTR || errno == EAGAIN)
297 ERR("could not read from fd %d: %s",
298 fd, strerror(errno));
308 _ethumbd_write_safe(int fd, const void *buf, ssize_t size)
320 r = write(fd, p, todo);
330 if (errno == EINTR || errno == EAGAIN)
334 ERR("could not write to fd %d: %s", fd, strerror(errno));
344 _ethumbd_child_write_op_new(struct _Ethumbd *ed, int index)
346 int id = ETHUMBD_OP_NEW;
347 _ethumbd_write_safe(ed->pipeout, &id, sizeof(id));
348 _ethumbd_write_safe(ed->pipeout, &index, sizeof(index));
352 _ethumbd_child_write_op_del(struct _Ethumbd *ed, int index)
354 int id = ETHUMBD_OP_DEL;
355 _ethumbd_write_safe(ed->pipeout, &id, sizeof(id));
356 _ethumbd_write_safe(ed->pipeout, &index, sizeof(index));
360 _ethumbd_pipe_str_write(int fd, const char *str)
365 len = strlen(str) + 1;
369 _ethumbd_write_safe(fd, &len, sizeof(len));
370 _ethumbd_write_safe(fd, str, len);
374 _ethumbd_pipe_str_read(int fd, char **str)
380 r = _ethumbd_read_safe(fd, &size, sizeof(size));
393 r = _ethumbd_read_safe(fd, buf, size);
405 _ethumbd_child_write_op_generate(struct _Ethumbd *ed, int index, const char *path, const char *key, const char *thumb_path, const char *thumb_key)
407 int id = ETHUMBD_OP_GENERATE;
409 _ethumbd_write_safe(ed->pipeout, &id, sizeof(id));
410 _ethumbd_write_safe(ed->pipeout, &index, sizeof(index));
412 _ethumbd_pipe_str_write(ed->pipeout, path);
413 _ethumbd_pipe_str_write(ed->pipeout, key);
414 _ethumbd_pipe_str_write(ed->pipeout, thumb_path);
415 _ethumbd_pipe_str_write(ed->pipeout, thumb_key);
419 _generated_cb(struct _Ethumbd *ed, Eina_Bool success, const char *thumb_path, const char *thumb_key)
421 int i = ed->queue.current;
423 DBG("thumbnail ready at: \"%s:%s\"\n", thumb_path, thumb_key);
425 if (ed->queue.table[i].used)
426 _ethumb_dbus_generated_signal
427 (ed, &ed->processing->id, thumb_path, thumb_key, success);
428 eina_stringshare_del(ed->processing->file);
429 eina_stringshare_del(ed->processing->key);
430 eina_stringshare_del(ed->processing->thumb);
431 eina_stringshare_del(ed->processing->thumb_key);
432 free(ed->processing);
433 ed->processing = NULL;
437 _ethumbd_fd_handler(void *data, Ecore_Fd_Handler *fd_handler)
439 struct _Ethumbd *ed = data;
442 char *thumb_path, *thumb_key;
444 if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR))
446 ERR("error on pipein! child exiting...\n");
447 ed->fd_handler = NULL;
448 ecore_main_loop_quit();
452 r = _ethumbd_read_safe(ed->pipein, &success, sizeof(success));
455 ERR("ethumbd child exited!\n");
456 ed->fd_handler = NULL;
460 r = _ethumbd_pipe_str_read(ed->pipein, &thumb_path);
461 r = _ethumbd_pipe_str_read(ed->pipein, &thumb_key);
462 _generated_cb(ed, success, thumb_path, thumb_key);
471 _ethumbd_pipe_write_setup(int fd, int type, const void *data)
474 const float *f_value;
476 _ethumbd_write_safe(fd, &type, sizeof(type));
483 case ETHUMBD_QUALITY:
484 case ETHUMBD_COMPRESS:
487 case ETHUMBD_DOCUMENT_PAGE:
488 case ETHUMBD_VIDEO_NTIMES:
489 case ETHUMBD_VIDEO_FPS:
491 _ethumbd_write_safe(fd, i_value, sizeof(*i_value));
495 case ETHUMBD_VIDEO_TIME:
496 case ETHUMBD_VIDEO_START:
497 case ETHUMBD_VIDEO_INTERVAL:
499 _ethumbd_write_safe(fd, f_value, sizeof(*f_value));
501 case ETHUMBD_DIRECTORY:
502 case ETHUMBD_CATEGORY:
503 case ETHUMBD_FRAME_FILE:
504 case ETHUMBD_FRAME_GROUP:
505 case ETHUMBD_FRAME_SWALLOW:
506 _ethumbd_pipe_str_write(fd, data);
508 case ETHUMBD_SETUP_FINISHED:
511 ERR("wrong ethumb setup parameter.\n");
516 _process_setup(struct _Ethumbd *ed)
518 int op_id = ETHUMBD_OP_SETUP;
519 int index = ed->queue.current;
520 int fd = ed->pipeout;
522 struct _Ethumb_Setup *setup = &ed->processing->setup;
524 _ethumbd_write_safe(ed->pipeout, &op_id, sizeof(op_id));
525 _ethumbd_write_safe(ed->pipeout, &index, sizeof(index));
527 if (setup->flags.fdo)
528 _ethumbd_pipe_write_setup(fd, ETHUMBD_FDO, &setup->fdo);
529 if (setup->flags.size)
531 _ethumbd_pipe_write_setup(fd, ETHUMBD_SIZE_W, &setup->tw);
532 _ethumbd_pipe_write_setup(fd, ETHUMBD_SIZE_H, &setup->th);
534 if (setup->flags.format)
535 _ethumbd_pipe_write_setup(fd, ETHUMBD_FORMAT, &setup->format);
536 if (setup->flags.aspect)
537 _ethumbd_pipe_write_setup(fd, ETHUMBD_ASPECT, &setup->aspect);
538 if (setup->flags.crop)
540 _ethumbd_pipe_write_setup(fd, ETHUMBD_CROP_X, &setup->cx);
541 _ethumbd_pipe_write_setup(fd, ETHUMBD_CROP_Y, &setup->cy);
543 if (setup->flags.quality)
544 _ethumbd_pipe_write_setup(fd, ETHUMBD_QUALITY, &setup->quality);
545 if (setup->flags.compress)
546 _ethumbd_pipe_write_setup(fd, ETHUMBD_COMPRESS, &setup->compress);
547 if (setup->flags.directory)
548 _ethumbd_pipe_write_setup(fd, ETHUMBD_DIRECTORY, setup->directory);
549 if (setup->flags.category)
550 _ethumbd_pipe_write_setup(fd, ETHUMBD_CATEGORY, setup->category);
551 if (setup->flags.frame)
553 _ethumbd_pipe_write_setup(fd, ETHUMBD_FRAME_FILE, setup->theme_file);
554 _ethumbd_pipe_write_setup(fd, ETHUMBD_FRAME_GROUP, setup->group);
555 _ethumbd_pipe_write_setup(fd, ETHUMBD_FRAME_SWALLOW, setup->swallow);
557 if (setup->flags.video_time)
558 _ethumbd_pipe_write_setup(fd, ETHUMBD_VIDEO_TIME, &setup->video_time);
559 if (setup->flags.video_start)
560 _ethumbd_pipe_write_setup(fd, ETHUMBD_VIDEO_START, &setup->video_start);
561 if (setup->flags.video_interval)
562 _ethumbd_pipe_write_setup(fd, ETHUMBD_VIDEO_INTERVAL,
563 &setup->video_interval);
564 if (setup->flags.video_ntimes)
565 _ethumbd_pipe_write_setup(fd, ETHUMBD_VIDEO_NTIMES, &setup->video_ntimes);
566 if (setup->flags.video_fps)
567 _ethumbd_pipe_write_setup(fd, ETHUMBD_VIDEO_FPS, &setup->video_fps);
568 if (setup->flags.document_page)
569 _ethumbd_pipe_write_setup(fd, ETHUMBD_DOCUMENT_PAGE,
570 &setup->document_page);
571 _ethumbd_pipe_write_setup(fd, ETHUMBD_SETUP_FINISHED, NULL);
574 if (setup->directory) eina_stringshare_del(setup->directory);
575 if (setup->category) eina_stringshare_del(setup->category);
576 if (setup->theme_file) eina_stringshare_del(setup->theme_file);
577 if (setup->group) eina_stringshare_del(setup->group);
578 if (setup->swallow) eina_stringshare_del(setup->swallow);
580 free(ed->processing);
581 ed->processing = NULL;
585 _process_file(struct _Ethumbd *ed)
587 _ethumbd_child_write_op_generate
588 (ed, ed->queue.current, ed->processing->file,
589 ed->processing->key, ed->processing->thumb, ed->processing->thumb_key);
593 _get_next_on_queue(struct _Ethumb_Queue *queue)
596 struct _Ethumb_Object *eobject;
600 if (i >= queue->count)
603 index = queue->list[i];
604 eobject = &(queue->table[index]);
605 while (!eobject->nqueue)
607 i = (i + 1) % queue->count;
609 index = queue->list[i];
610 eobject = &(queue->table[index]);
613 return queue->list[i];
617 _process_queue_cb(void *data)
619 struct _Ethumb_Object *eobject;
621 struct _Ethumbd *ed = data;
622 struct _Ethumb_Queue *queue = &ed->queue;
623 struct _Ethumb_Request *request;
632 _ethumbd_timeout_start(ed);
637 i = _get_next_on_queue(queue);
638 eobject = &(queue->table[i]);
640 request = eina_list_data_get(eobject->queue);
641 eobject->queue = eina_list_remove_list(eobject->queue, eobject->queue);
642 ed->queue.current = i;
643 DBG("processing file: \"%s:%s\"...\n", request->file,
645 ed->processing = request;
652 _ethumb_dbus_inc_min_id(eobject);
663 _process_queue_start(struct _Ethumbd *ed)
666 ed->idler = ecore_idler_add(_process_queue_cb, ed);
670 _process_queue_stop(struct _Ethumbd *ed)
674 ecore_idler_del(ed->idler);
680 _ethumb_table_append(struct _Ethumbd *ed)
684 struct _Ethumb_Queue *q = &ed->queue;
686 if (q->count == q->max_count)
688 int new_max = q->max_count + 5;
691 start = q->max_count;
692 size = new_max - q->max_count;
694 q->table = realloc(q->table, new_max * sizeof(struct _Ethumb_Object));
695 q->list = realloc(q->list, new_max * sizeof(int));
696 memset(&q->table[start], 0, size * sizeof(struct _Ethumb_Object));
698 q->max_count = new_max;
701 for (i = 0; i < q->max_count; i++)
703 if (!q->table[i].used)
707 snprintf(buf, sizeof(buf), "%s/%d", _ethumb_dbus_path, i);
708 q->table[i].used = 1;
709 q->table[i].path = eina_stringshare_add(buf);
710 q->table[i].max_id = -1;
711 q->table[i].min_id = -1;
712 q->list[q->count] = i;
714 DBG("new object: %s, index = %d, count = %d\n", buf, i, q->count);
720 _get_index_for_path(const char *path)
724 n = sscanf(path, "/org/enlightenment/Ethumb/%d", &i);
731 _ethumb_table_del(struct _Ethumbd *ed, int i)
736 struct _Ethumb_Queue *q = &ed->queue;
737 struct _Ethumb_Object_Data *odata;
739 eina_stringshare_del(q->table[i].path);
741 l = q->table[i].queue;
744 struct _Ethumb_Request *request = l->data;
745 eina_stringshare_del(request->file);
746 eina_stringshare_del(request->key);
747 eina_stringshare_del(request->thumb);
748 eina_stringshare_del(request->thumb_key);
750 l = eina_list_remove_list(l, l);
752 q->nqueue -= q->table[i].nqueue;
754 il = e_dbus_object_interfaces_get(q->table[i].dbus_obj);
757 e_dbus_object_interface_detach(q->table[i].dbus_obj, il->data);
758 il = e_dbus_object_interfaces_get(q->table[i].dbus_obj);
760 odata = e_dbus_object_data_get(q->table[i].dbus_obj);
762 e_dbus_object_free(q->table[i].dbus_obj);
764 memset(&(q->table[i]), 0, sizeof(struct _Ethumb_Object));
765 for (j = 0; j < q->count; j++)
768 q->list[j] = q->list[q->count - 1];
772 _ethumbd_child_write_op_del(ed, i);
773 if (!q->count && !ed->processing)
774 _ethumbd_timeout_start(ed);
778 _ethumb_table_clear(struct _Ethumbd *ed)
782 for (i = 0; i < ed->queue.max_count; i++)
783 if (ed->queue.table[i].used)
784 _ethumb_table_del(ed, i);
788 _name_owner_changed_cb(void *data, DBusMessage *msg)
791 struct _Ethumbd *ed = data;
792 struct _Ethumb_Queue *q = &ed->queue;
793 const char *name, *from, *to;
796 dbus_error_init(&err);
797 if (!dbus_message_get_args(msg, &err,
798 DBUS_TYPE_STRING, &name,
799 DBUS_TYPE_STRING, &from,
800 DBUS_TYPE_STRING, &to,
803 ERR("could not get NameOwnerChanged arguments: %s: %s\n",
804 err.name, err.message);
805 dbus_error_free(&err);
809 DBG("NameOwnerChanged: name = %s, from = %s, to = %s\n", name, from, to);
811 if (from[0] == '\0' || to[0] != '\0')
814 from = eina_stringshare_add(from);
815 for (i = 0; i < q->max_count; i++)
817 if (q->table[i].used && q->table[i].client == from)
819 _ethumb_table_del(ed, i);
820 DBG("deleting [%d] from queue table.\n", i);
826 _ethumb_dbus_add_name_owner_changed_cb(struct _Ethumbd *ed)
828 ed->name_owner_changed_handler = e_dbus_signal_handler_add
829 (ed->conn, fdo_bus_name, fdo_path, fdo_interface, "NameOwnerChanged",
830 _name_owner_changed_cb, ed);
834 _ethumb_dbus_ethumb_new_cb(E_DBus_Object *object, DBusMessage *msg)
837 DBusMessageIter iter;
838 E_DBus_Object *dbus_object;
839 struct _Ethumb_Object_Data *odata;
841 const char *return_path = "";
845 ed = e_dbus_object_data_get(object);
846 client = dbus_message_get_sender(msg);
850 i = _ethumb_table_append(ed);
852 odata = calloc(1, sizeof(*odata));
856 ed->queue.table[i].client = eina_stringshare_add(client);
857 return_path = ed->queue.table[i].path;
859 dbus_object = e_dbus_object_add(ed->conn, return_path, odata);
862 ERR("could not create dbus_object.\n");
868 e_dbus_object_interface_attach(dbus_object, ed->objects_iface);
869 ed->queue.table[i].dbus_obj = dbus_object;
871 _ethumbd_child_write_op_new(ed, i);
872 _ethumbd_timeout_stop(ed);
875 reply = dbus_message_new_method_return(msg);
876 dbus_message_iter_init_append(reply, &iter);
877 dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
882 static struct _Ethumb_DBus_Method_Table _ethumb_dbus_methods[] =
884 {"new", "", "o", _ethumb_dbus_ethumb_new_cb},
885 {NULL, NULL, NULL, NULL}
889 _ethumb_dbus_get_bytearray(DBusMessageIter *iter)
893 DBusMessageIter riter;
896 el_type = dbus_message_iter_get_element_type(iter);
897 if (el_type != DBUS_TYPE_BYTE)
899 ERR("not an byte array element.\n");
903 dbus_message_iter_recurse(iter, &riter);
904 dbus_message_iter_get_fixed_array(&riter, &result, &length);
906 if (result[0] == '\0')
909 return eina_stringshare_add(result);
913 _ethumb_dbus_append_bytearray(DBusMessageIter *iter, const char *string)
915 DBusMessageIter viter;
920 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &viter);
921 dbus_message_iter_append_fixed_array
922 (&viter, DBUS_TYPE_BYTE, &string, strlen(string) + 1);
923 dbus_message_iter_close_container(iter, &viter);
927 _ethumb_dbus_queue_add_cb(E_DBus_Object *object, DBusMessage *msg)
930 DBusMessageIter iter;
931 const char *file, *key;
932 const char *thumb, *thumb_key;
933 struct _Ethumb_Object_Data *odata;
934 struct _Ethumb_Object *eobject;
936 struct _Ethumb_Request *request;
937 dbus_int32_t id = -1;
939 dbus_message_iter_init(msg, &iter);
940 dbus_message_iter_get_basic(&iter, &id);
941 dbus_message_iter_next(&iter);
942 file = _ethumb_dbus_get_bytearray(&iter);
943 dbus_message_iter_next(&iter);
944 key = _ethumb_dbus_get_bytearray(&iter);
945 dbus_message_iter_next(&iter);
946 thumb = _ethumb_dbus_get_bytearray(&iter);
947 dbus_message_iter_next(&iter);
948 thumb_key = _ethumb_dbus_get_bytearray(&iter);
952 ERR("no filename given.\n");
956 odata = e_dbus_object_data_get(object);
959 ERR("could not get dbus_object data.\n");
964 eobject = &(ed->queue.table[odata->index]);
965 if (!_ethumb_dbus_check_id(eobject, id))
967 request = calloc(1, sizeof(*request));
969 request->file = file;
971 request->thumb = thumb;
972 request->thumb_key = thumb_key;
973 eobject->queue = eina_list_append(eobject->queue, request);
976 _ethumb_dbus_inc_max_id(eobject, id);
978 _process_queue_start(ed);
981 reply = dbus_message_new_method_return(msg);
982 dbus_message_iter_init_append(reply, &iter);
983 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &id);
988 _ethumb_dbus_queue_remove_cb(E_DBus_Object *object, DBusMessage *msg)
991 DBusMessageIter iter;
993 struct _Ethumb_Object_Data *odata;
994 struct _Ethumb_Object *eobject;
995 struct _Ethumb_Request *request;
1000 dbus_message_iter_init(msg, &iter);
1001 dbus_message_iter_get_basic(&iter, &id);
1003 odata = e_dbus_object_data_get(object);
1006 ERR("could not get dbus_object data.\n");
1011 eobject = &ed->queue.table[odata->index];
1016 if (id == request->id)
1024 eina_stringshare_del(request->file);
1025 eina_stringshare_del(request->key);
1026 eina_stringshare_del(request->thumb);
1027 eina_stringshare_del(request->thumb_key);
1029 eobject->queue = eina_list_remove_list(eobject->queue, l);
1032 _ethumb_dbus_inc_min_id(eobject);
1036 reply = dbus_message_new_method_return(msg);
1037 dbus_message_iter_init_append(reply, &iter);
1038 dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &r);
1043 _ethumb_dbus_queue_clear_cb(E_DBus_Object *object, DBusMessage *msg)
1046 struct _Ethumb_Object_Data *odata;
1047 struct _Ethumb_Object *eobject;
1048 struct _Ethumbd *ed;
1051 odata = e_dbus_object_data_get(object);
1054 ERR("could not get dbus_object data.\n");
1059 eobject = &ed->queue.table[odata->index];
1063 struct _Ethumb_Request *request = l->data;
1064 eina_stringshare_del(request->file);
1065 eina_stringshare_del(request->key);
1066 eina_stringshare_del(request->thumb);
1067 eina_stringshare_del(request->thumb_key);
1069 l = eina_list_remove_list(l, l);
1071 ed->queue.nqueue -= eobject->nqueue;
1072 eobject->nqueue = 0;
1075 reply = dbus_message_new_method_return(msg);
1080 _ethumb_dbus_delete_cb(E_DBus_Object *object, DBusMessage *msg)
1083 DBusMessageIter iter;
1084 struct _Ethumb_Object_Data *odata;
1085 struct _Ethumbd *ed;
1087 dbus_message_iter_init(msg, &iter);
1088 reply = dbus_message_new_method_return(msg);
1090 odata = e_dbus_object_data_get(object);
1093 ERR("could not get dbus_object data for del_cb.\n");
1097 _ethumb_table_del(ed, odata->index);
1104 _ethumb_dbus_fdo_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request __UNUSED__)
1109 type = dbus_message_iter_get_arg_type(iter);
1110 if (type != DBUS_TYPE_INT32)
1112 ERR("invalid param for fdo_set.\n");
1116 dbus_message_iter_get_basic(iter, &fdo);
1117 DBG("setting fdo to: %d\n", fdo);
1123 _ethumb_dbus_size_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1125 DBusMessageIter oiter;
1129 type = dbus_message_iter_get_arg_type(iter);
1130 if (type != DBUS_TYPE_STRUCT)
1132 ERR("invalid param for size_set.\n");
1136 dbus_message_iter_recurse(iter, &oiter);
1137 dbus_message_iter_get_basic(&oiter, &w);
1138 dbus_message_iter_next(&oiter);
1139 dbus_message_iter_get_basic(&oiter, &h);
1140 DBG("setting size to: %dx%d\n", w, h);
1141 request->setup.flags.size = 1;
1142 request->setup.tw = w;
1143 request->setup.th = h;
1149 _ethumb_dbus_format_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1152 dbus_int32_t format;
1154 type = dbus_message_iter_get_arg_type(iter);
1155 if (type != DBUS_TYPE_INT32)
1157 ERR("invalid param for format_set.\n");
1161 dbus_message_iter_get_basic(iter, &format);
1162 DBG("setting format to: %d\n", format);
1163 request->setup.flags.format = 1;
1164 request->setup.format = format;
1170 _ethumb_dbus_aspect_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1173 dbus_int32_t aspect;
1175 type = dbus_message_iter_get_arg_type(iter);
1176 if (type != DBUS_TYPE_INT32)
1178 ERR("invalid param for aspect_set.\n");
1182 dbus_message_iter_get_basic(iter, &aspect);
1183 DBG("setting aspect to: %d\n", aspect);
1184 request->setup.flags.aspect = 1;
1185 request->setup.aspect = aspect;
1191 _ethumb_dbus_crop_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1193 DBusMessageIter oiter;
1197 type = dbus_message_iter_get_arg_type(iter);
1198 if (type != DBUS_TYPE_STRUCT)
1200 ERR("invalid param for crop_set.\n");
1204 dbus_message_iter_recurse(iter, &oiter);
1205 dbus_message_iter_get_basic(&oiter, &x);
1206 dbus_message_iter_next(&oiter);
1207 dbus_message_iter_get_basic(&oiter, &y);
1208 DBG("setting crop to: %3.2f,%3.2f\n", x, y);
1209 request->setup.flags.crop = 1;
1210 request->setup.cx = x;
1211 request->setup.cy = y;
1217 _ethumb_dbus_quality_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1220 dbus_int32_t quality;
1222 type = dbus_message_iter_get_arg_type(iter);
1223 if (type != DBUS_TYPE_INT32)
1225 ERR("invalid param for quality_set.\n");
1229 dbus_message_iter_get_basic(iter, &quality);
1230 DBG("setting quality to: %d\n", quality);
1231 request->setup.flags.quality = 1;
1232 request->setup.quality = quality;
1239 _ethumb_dbus_compress_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1242 dbus_int32_t compress;
1244 type = dbus_message_iter_get_arg_type(iter);
1245 if (type != DBUS_TYPE_INT32)
1247 ERR("invalid param for compress_set.\n");
1251 dbus_message_iter_get_basic(iter, &compress);
1252 DBG("setting compress to: %d\n", compress);
1253 request->setup.flags.compress = 1;
1254 request->setup.compress = compress;
1260 _ethumb_dbus_frame_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1262 DBusMessageIter oiter;
1264 const char *file, *group, *swallow;
1266 type = dbus_message_iter_get_arg_type(iter);
1267 if (type != DBUS_TYPE_STRUCT)
1269 ERR("invalid param for frame_set.\n");
1273 dbus_message_iter_recurse(iter, &oiter);
1274 file = _ethumb_dbus_get_bytearray(&oiter);
1275 dbus_message_iter_next(&oiter);
1276 group = _ethumb_dbus_get_bytearray(&oiter);
1277 dbus_message_iter_next(&oiter);
1278 swallow = _ethumb_dbus_get_bytearray(&oiter);
1279 DBG("setting frame to \"%s:%s:%s\"\n", file, group, swallow);
1280 request->setup.flags.frame = 1;
1281 request->setup.theme_file = eina_stringshare_add(file);
1282 request->setup.group = eina_stringshare_add(group);
1283 request->setup.swallow = eina_stringshare_add(swallow);
1289 _ethumb_dbus_directory_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1292 const char *directory;
1294 type = dbus_message_iter_get_arg_type(iter);
1295 if (type != DBUS_TYPE_ARRAY)
1297 ERR("invalid param for dir_path_set.\n");
1301 directory = _ethumb_dbus_get_bytearray(iter);
1302 DBG("setting directory to: %s\n", directory);
1303 request->setup.flags.directory = 1;
1304 request->setup.directory = eina_stringshare_add(directory);
1310 _ethumb_dbus_category_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1313 const char *category;
1315 type = dbus_message_iter_get_arg_type(iter);
1316 if (type != DBUS_TYPE_ARRAY)
1318 ERR("invalid param for category.\n");
1322 category = _ethumb_dbus_get_bytearray(iter);
1323 DBG("setting category to: %s\n", category);
1324 request->setup.flags.category = 1;
1325 request->setup.category = eina_stringshare_add(category);
1331 _ethumb_dbus_video_time_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1336 type = dbus_message_iter_get_arg_type(iter);
1337 if (type != DBUS_TYPE_DOUBLE)
1339 ERR("invalid param for video_time_set.\n");
1343 dbus_message_iter_get_basic(iter, &video_time);
1344 DBG("setting video_time to: %3.2f\n", video_time);
1345 request->setup.flags.video_time = 1;
1346 request->setup.video_time = video_time;
1352 _ethumb_dbus_video_start_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1357 type = dbus_message_iter_get_arg_type(iter);
1358 if (type != DBUS_TYPE_DOUBLE)
1360 ERR("invalid param for video_start_set.\n");
1364 dbus_message_iter_get_basic(iter, &video_start);
1365 DBG("setting video_start to: %3.2f\n", video_start);
1366 request->setup.flags.video_start = 1;
1367 request->setup.video_start = video_start;
1373 _ethumb_dbus_video_interval_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1376 double video_interval;
1378 type = dbus_message_iter_get_arg_type(iter);
1379 if (type != DBUS_TYPE_DOUBLE)
1381 ERR("invalid param for video_interval_set.\n");
1385 dbus_message_iter_get_basic(iter, &video_interval);
1386 DBG("setting video_interval to: %3.2f\n", video_interval);
1387 request->setup.flags.video_interval = 1;
1388 request->setup.video_interval = video_interval;
1394 _ethumb_dbus_video_ntimes_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1399 type = dbus_message_iter_get_arg_type(iter);
1400 if (type != DBUS_TYPE_INT32)
1402 ERR("invalid param for video_ntimes_set.\n");
1406 dbus_message_iter_get_basic(iter, &video_ntimes);
1407 DBG("setting video_ntimes to: %3.2d\n", video_ntimes);
1408 request->setup.flags.video_ntimes = 1;
1409 request->setup.video_ntimes = video_ntimes;
1415 _ethumb_dbus_video_fps_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1420 type = dbus_message_iter_get_arg_type(iter);
1421 if (type != DBUS_TYPE_INT32)
1423 ERR("invalid param for video_fps_set.\n");
1427 dbus_message_iter_get_basic(iter, &video_fps);
1428 DBG("setting video_fps to: %3.2d\n", video_fps);
1429 request->setup.flags.video_fps = 1;
1430 request->setup.video_fps = video_fps;
1436 _ethumb_dbus_document_page_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1439 dbus_int32_t document_page;
1441 type = dbus_message_iter_get_arg_type(iter);
1442 if (type != DBUS_TYPE_INT32)
1444 ERR("invalid param for document_page_set.\n");
1448 dbus_message_iter_get_basic(iter, &document_page);
1449 DBG("setting document_page to: %d\n", document_page);
1450 request->setup.flags.document_page = 1;
1451 request->setup.document_page = document_page;
1459 int (*setup_func)(struct _Ethumb_Object *eobject, DBusMessageIter *iter, struct _Ethumb_Request *request);
1461 {"fdo", _ethumb_dbus_fdo_set},
1462 {"size", _ethumb_dbus_size_set},
1463 {"format", _ethumb_dbus_format_set},
1464 {"aspect", _ethumb_dbus_aspect_set},
1465 {"crop", _ethumb_dbus_crop_set},
1466 {"quality", _ethumb_dbus_quality_set},
1467 {"compress", _ethumb_dbus_compress_set},
1468 {"frame", _ethumb_dbus_frame_set},
1469 {"directory", _ethumb_dbus_directory_set},
1470 {"category", _ethumb_dbus_category_set},
1471 {"video_time", _ethumb_dbus_video_time_set},
1472 {"video_start", _ethumb_dbus_video_start_set},
1473 {"video_interval", _ethumb_dbus_video_interval_set},
1474 {"video_ntimes", _ethumb_dbus_video_ntimes_set},
1475 {"video_fps", _ethumb_dbus_video_fps_set},
1476 {"document_page", _ethumb_dbus_document_page_set},
1481 _ethumb_dbus_ethumb_setup_parse_element(struct _Ethumb_Object *eobject, DBusMessageIter *iter, struct _Ethumb_Request *request)
1483 DBusMessageIter viter, diter;
1487 dbus_message_iter_recurse(iter, &diter);
1488 dbus_message_iter_get_basic(&diter, &option);
1489 dbus_message_iter_next(&diter);
1492 for (i = 0; _option_cbs[i].option; i++)
1493 if (!strcmp(_option_cbs[i].option, option))
1501 ERR("ethumb_setup invalid option: %s\n", option);
1505 dbus_message_iter_recurse(&diter, &viter);
1506 return _option_cbs[i].setup_func(eobject, &viter, request);
1510 _ethumb_dbus_ethumb_setup_cb(E_DBus_Object *object, DBusMessage *msg)
1513 DBusMessageIter iter, aiter;
1514 struct _Ethumb_Object_Data *odata;
1515 struct _Ethumbd *ed;
1516 struct _Ethumb_Object *eobject;
1517 struct _Ethumb_Request *request;
1521 dbus_message_iter_init(msg, &iter);
1522 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1524 ERR("wrong parameters.\n");
1528 odata = e_dbus_object_data_get(object);
1531 ERR("could not get dbus_object data for setup_cb.\n");
1536 eobject = &ed->queue.table[odata->index];
1538 request = calloc(1, sizeof(*request));
1540 dbus_message_iter_recurse(&iter, &aiter);
1541 atype = dbus_message_iter_get_arg_type(&aiter);
1544 while (atype != DBUS_TYPE_INVALID)
1546 if (!_ethumb_dbus_ethumb_setup_parse_element(eobject, &aiter, request))
1548 dbus_message_iter_next(&aiter);
1549 atype = dbus_message_iter_get_arg_type(&aiter);
1552 eobject->queue = eina_list_append(eobject->queue, request);
1557 reply = dbus_message_new_method_return(msg);
1558 dbus_message_iter_init_append(reply, &iter);
1559 dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &r);
1565 _ethumb_dbus_generated_signal(struct _Ethumbd *ed, int *id, const char *thumb_path, const char *thumb_key, Eina_Bool success)
1567 DBusMessage *signal;
1570 DBusMessageIter iter;
1577 current = ed->queue.current;
1578 opath = ed->queue.table[current].path;
1579 signal = dbus_message_new_signal
1580 (opath, _ethumb_dbus_objects_interface, "generated");
1582 dbus_message_iter_init_append(signal, &iter);
1583 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &id32);
1584 _ethumb_dbus_append_bytearray(&iter, thumb_path);
1585 _ethumb_dbus_append_bytearray(&iter, thumb_key);
1586 dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &value);
1588 e_dbus_message_send(ed->conn, signal, NULL, -1, NULL);
1589 dbus_message_unref(signal);
1592 static struct _Ethumb_DBus_Method_Table _ethumb_dbus_objects_methods[] = {
1593 {"queue_add", "iayayayay", "i", _ethumb_dbus_queue_add_cb},
1594 {"queue_remove", "i", "b", _ethumb_dbus_queue_remove_cb},
1595 {"clear_queue", "", "", _ethumb_dbus_queue_clear_cb},
1596 {"ethumb_setup", "a{sv}", "b", _ethumb_dbus_ethumb_setup_cb},
1597 {"delete", "", "", _ethumb_dbus_delete_cb},
1598 {NULL, NULL, NULL, NULL}
1601 static struct _Ethumb_DBus_Signal_Table _ethumb_dbus_objects_signals[] = {
1602 {"generated", "xayayb"},
1607 _ethumb_dbus_interface_elements_add(E_DBus_Interface *iface, struct _Ethumb_DBus_Method_Table *mtable, struct _Ethumb_DBus_Signal_Table *stable)
1610 while (mtable && mtable[++i].name != NULL)
1611 if (!e_dbus_interface_method_add(iface,
1613 mtable[i].signature,
1615 mtable[i].function))
1619 while (stable && stable[++i].name != NULL)
1620 if (!e_dbus_interface_signal_add(iface,
1622 stable[i].signature))
1628 _ethumb_dbus_request_name_cb(void *data, DBusMessage *msg __UNUSED__, DBusError *err)
1630 E_DBus_Object *dbus_object;
1631 struct _Ethumbd *ed = data;
1634 if (dbus_error_is_set(err))
1636 ERR("request name error: %s\n", err->message);
1637 dbus_error_free(err);
1638 e_dbus_connection_close(ed->conn);
1642 dbus_object = e_dbus_object_add(ed->conn, _ethumb_dbus_path, ed);
1645 ed->dbus_obj = dbus_object;
1646 ed->eiface = e_dbus_interface_new(_ethumb_dbus_interface);
1649 ERR("could not create interface.\n");
1652 r = _ethumb_dbus_interface_elements_add(ed->eiface,
1653 _ethumb_dbus_methods, NULL);
1656 ERR("could not add methods to the interface.\n");
1657 e_dbus_interface_unref(ed->eiface);
1660 e_dbus_object_interface_attach(dbus_object, ed->eiface);
1662 ed->objects_iface = e_dbus_interface_new(_ethumb_dbus_objects_interface);
1663 if (!ed->objects_iface)
1665 ERR("could not create interface.\n");
1669 r = _ethumb_dbus_interface_elements_add(ed->objects_iface,
1670 _ethumb_dbus_objects_methods,
1671 _ethumb_dbus_objects_signals);
1674 ERR("ERROR: could not setup objects interface methods.\n");
1675 e_dbus_interface_unref(ed->objects_iface);
1679 _ethumb_dbus_add_name_owner_changed_cb(ed);
1681 _ethumbd_timeout_start(ed);
1685 _ethumb_dbus_setup(struct _Ethumbd *ed)
1688 (ed->conn, _ethumb_dbus_bus_name, 0, _ethumb_dbus_request_name_cb, ed);
1694 _ethumb_dbus_finish(struct _Ethumbd *ed)
1696 _process_queue_stop(ed);
1697 _ethumb_table_clear(ed);
1698 e_dbus_signal_handler_del(ed->conn, ed->name_owner_changed_handler);
1699 e_dbus_interface_unref(ed->objects_iface);
1700 e_dbus_interface_unref(ed->eiface);
1701 e_dbus_object_free(ed->dbus_obj);
1702 free(ed->queue.table);
1703 free(ed->queue.list);
1707 _ethumbd_spawn(struct _Ethumbd *ed)
1709 int pparent[2]; // parent writes here
1710 int pchild[2]; // child writes here
1713 if (pipe(pparent) == -1)
1715 ERR("could not create parent pipe.\n");
1719 if (pipe(pchild) == -1)
1721 ERR("could not create child pipe.\n");
1728 ERR("fork error.\n");
1736 ethumbd_child_start(pparent[0], pchild[1]);
1743 ed->pipeout = pparent[1];
1744 ed->pipein = pchild[0];
1745 ed->fd_handler = ecore_main_fd_handler_add
1746 (ed->pipein, ECORE_FD_READ | ECORE_FD_ERROR,
1747 _ethumbd_fd_handler, ed, NULL, NULL);
1753 main(int argc, char *argv[])
1755 Eina_Bool quit_option = 0;
1760 double timeout = -1;
1762 memset(&ed, 0, sizeof(ed));
1768 child = _ethumbd_spawn(&ed);
1783 ERR("could not init e_dbus.\n");
1788 Ecore_Getopt_Value values[] = {
1789 ECORE_GETOPT_VALUE_DOUBLE(timeout),
1790 ECORE_GETOPT_VALUE_BOOL(quit_option),
1791 ECORE_GETOPT_VALUE_BOOL(quit_option),
1792 ECORE_GETOPT_VALUE_BOOL(quit_option),
1793 ECORE_GETOPT_VALUE_BOOL(quit_option),
1794 ECORE_GETOPT_VALUE_NONE
1797 arg_index = ecore_getopt_parse(&optdesc, values, argc, argv);
1800 ERR("Could not parse arguments.\n");
1808 ed.conn = e_dbus_bus_get(DBUS_BUS_SESSION);
1811 ERR("could not connect to session bus.\n");
1816 ed.timeout = timeout;
1818 if (!_ethumb_dbus_setup(&ed))
1820 e_dbus_connection_close(ed.conn);
1821 ERR("could not setup dbus connection.\n");
1826 ecore_main_loop_begin();
1827 _ethumb_dbus_finish(&ed);