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>
35 #include <Ecore_Getopt.h>
39 #include "ethumbd_private.h"
45 #define MAX_ID 2000000
47 #define DBG(...) EINA_LOG_DBG(__VA_ARGS__)
48 #define INF(...) EINA_LOG_INFO(__VA_ARGS__)
49 #define WRN(...) EINA_LOG_WARN(__VA_ARGS__)
50 #define ERR(...) EINA_LOG_ERR(__VA_ARGS__)
51 #define CRIT(...) EINA_LOG_CRIT(__VA_ARGS__)
53 static const char _ethumb_dbus_bus_name[] = "org.enlightenment.Ethumb";
54 static const char _ethumb_dbus_interface[] = "org.enlightenment.Ethumb";
55 static const char _ethumb_dbus_objects_interface[] = "org.enlightenment.Ethumb.objects";
56 static const char _ethumb_dbus_path[] = "/org/enlightenment/Ethumb";
57 static const char fdo_interface[] = "org.freedesktop.DBus";
58 static const char fdo_bus_name[] = "org.freedesktop.DBus";
59 static const char fdo_path[] = "/org/freedesktop/DBus";
70 Eina_Bool quality : 1;
71 Eina_Bool compress : 1;
72 Eina_Bool directory : 1;
73 Eina_Bool category : 1;
75 Eina_Bool video_time : 1;
76 Eina_Bool video_start : 1;
77 Eina_Bool video_interval : 1;
78 Eina_Bool video_ntimes : 1;
79 Eina_Bool video_fps : 1;
80 Eina_Bool document_page : 1;
89 const char *directory;
91 const char *theme_file;
97 unsigned int video_ntimes;
98 unsigned int video_fps;
99 unsigned int document_page;
102 struct _Ethumb_Request
105 const char *file, *key;
106 const char *thumb, *thumb_key;
107 struct _Ethumb_Setup setup;
110 struct _Ethumb_Object
120 E_DBus_Object *dbus_obj;
130 struct _Ethumb_Object *table;
137 Ecore_Event_Handler *data_cb;
138 Ecore_Event_Handler *del_cb;
139 char *bufcmd; // buffer to read commands from slave
140 int scmd; // size of command to read
141 int pcmd; // position in the command buffer
146 E_DBus_Connection *conn;
147 E_DBus_Signal_Handler *name_owner_changed_handler;
148 E_DBus_Interface *eiface, *objects_iface;
149 E_DBus_Object *dbus_obj;
151 struct _Ethumb_Request *processing;
152 struct _Ethumb_Queue queue;
154 Ecore_Timer *timeout_timer;
155 struct _Ethumb_Slave slave;
158 struct _Ethumb_Object_Data
164 struct _Ethumb_DBus_Method_Table
167 const char *signature;
169 E_DBus_Method_Cb function;
172 struct _Ethumb_DBus_Signal_Table
175 const char *signature;
178 const Ecore_Getopt optdesc = {
182 "(C) 2009 - ProFUSION embedded systems",
183 "LGPL v3 - GNU Lesser General Public License",
186 "ethumbd uses the Ethumb library to create thumbnails for any "
187 "program that requests it (now just by dbus).\n",
190 ECORE_GETOPT_STORE_DOUBLE
191 ('t', "timeout", "finish ethumbd after <timeout> seconds of no activity."),
192 ECORE_GETOPT_LICENSE('L', "license"),
193 ECORE_GETOPT_COPYRIGHT('C', "copyright"),
194 ECORE_GETOPT_VERSION('V', "version"),
195 ECORE_GETOPT_HELP('h', "help"),
196 ECORE_GETOPT_SENTINEL
200 static void _ethumb_dbus_generated_signal(struct _Ethumbd *ed, int *id, const char *thumb_path, const char *thumb_key, Eina_Bool success);
201 static int _ethumbd_slave_spawn(struct _Ethumbd *ed);
204 _ethumbd_timeout_cb(void *data)
206 struct _Ethumbd *ed = data;
208 ecore_main_loop_quit();
209 ed->timeout_timer = NULL;
215 _ethumbd_timeout_start(struct _Ethumbd *ed)
220 if (!ed->timeout_timer)
221 ed->timeout_timer = ecore_timer_add(ed->timeout, _ethumbd_timeout_cb, ed);
225 _ethumbd_timeout_stop(struct _Ethumbd *ed)
227 if (!ed->timeout_timer)
230 ecore_timer_del(ed->timeout_timer);
231 ed->timeout_timer = NULL;
235 _ethumb_dbus_check_id(struct _Ethumb_Object *eobject, int id)
237 if (id < 0 || id > MAX_ID)
240 if (eobject->min_id < eobject->max_id)
241 return id < eobject->min_id || id > eobject->max_id;
242 else if (eobject->min_id > eobject->max_id)
243 return id < eobject->min_id && id > eobject->max_id;
245 return id != eobject->max_id;
249 _ethumb_dbus_inc_max_id(struct _Ethumb_Object *eobject, int id)
251 if (eobject->min_id < 0 && eobject->max_id < 0)
252 eobject->min_id = id;
254 eobject->max_id = id;
258 _ethumb_dbus_inc_min_id(struct _Ethumb_Object *eobject)
265 struct _Ethumb_Request *request = l->data;
266 if (request->id >= 0)
268 eobject->min_id = request->id;
277 eobject->min_id = -1;
278 eobject->max_id = -1;
283 _ethumbd_write_safe(struct _Ethumbd *ed, const void *buf, ssize_t size)
288 ERR("slave process isn't running.\n");
292 ecore_exe_send(ed->slave.exe, buf, size);
297 _ethumbd_child_write_op_new(struct _Ethumbd *ed, int index)
299 int id = ETHUMBD_OP_NEW;
300 _ethumbd_write_safe(ed, &id, sizeof(id));
301 _ethumbd_write_safe(ed, &index, sizeof(index));
305 _ethumbd_child_write_op_del(struct _Ethumbd *ed, int index)
307 int id = ETHUMBD_OP_DEL;
308 _ethumbd_write_safe(ed, &id, sizeof(id));
309 _ethumbd_write_safe(ed, &index, sizeof(index));
313 _ethumbd_pipe_str_write(struct _Ethumbd *ed, const char *str)
318 len = strlen(str) + 1;
322 _ethumbd_write_safe(ed, &len, sizeof(len));
323 _ethumbd_write_safe(ed, str, len);
327 _ethumbd_child_write_op_generate(struct _Ethumbd *ed, int index, const char *path, const char *key, const char *thumb_path, const char *thumb_key)
329 int id = ETHUMBD_OP_GENERATE;
331 _ethumbd_write_safe(ed, &id, sizeof(id));
332 _ethumbd_write_safe(ed, &index, sizeof(index));
334 _ethumbd_pipe_str_write(ed, path);
335 _ethumbd_pipe_str_write(ed, key);
336 _ethumbd_pipe_str_write(ed, thumb_path);
337 _ethumbd_pipe_str_write(ed, thumb_key);
341 _generated_cb(struct _Ethumbd *ed, Eina_Bool success, const char *thumb_path, const char *thumb_key)
343 int i = ed->queue.current;
345 DBG("thumbnail ready at: \"%s:%s\"\n", thumb_path, thumb_key);
347 if (ed->queue.table[i].used)
348 _ethumb_dbus_generated_signal
349 (ed, &ed->processing->id, thumb_path, thumb_key, success);
350 eina_stringshare_del(ed->processing->file);
351 eina_stringshare_del(ed->processing->key);
352 eina_stringshare_del(ed->processing->thumb);
353 eina_stringshare_del(ed->processing->thumb_key);
354 free(ed->processing);
355 ed->processing = NULL;
359 _write_safe(int fd, void *data, size_t size)
361 unsigned char *buf = data;
365 size_t r = write(fd, buf, todo);
371 else if ((r < 0) && (errno != EINTR))
373 ERR("could not write to fd=%d: %s", fd, strerror(errno));
381 _ethumbd_slave_cmd_ready(struct _Ethumbd *ed)
383 char *bufcmd = ed->slave.bufcmd;
385 char *thumb_path, *thumb_key;
386 int *size_path, *size_key;
389 success = (Eina_Bool *)bufcmd;
390 bufcmd += sizeof(*success);
392 size_path = (int *)bufcmd;
393 bufcmd += sizeof(*size_path);
395 _write_safe(STDERR_FILENO, bufcmd, ed->slave.scmd);
398 bufcmd += *size_path;
400 size_key = (int *)bufcmd;
401 bufcmd += sizeof(*size_key);
405 _generated_cb(ed, *success, thumb_path, thumb_key);
407 free(ed->slave.bufcmd);
408 ed->slave.bufcmd = NULL;
413 _ethumbd_slave_alloc_cmd(struct _Ethumbd *ed, int ssize, char *sdata)
417 if (ed->slave.bufcmd)
421 if (ssize < sizeof(*scmd)) {
422 ERR("could not read size of command.\n");
425 ed->slave.bufcmd = malloc(*scmd);
426 ed->slave.scmd = *scmd;
429 return sizeof(*scmd);
433 _ethumbd_slave_data_read_cb(void *data, int type, void *event)
435 struct _Ethumbd *ed = data;
436 Ecore_Exe_Event_Data *ev = event;
440 if (ev->exe != ed->slave.exe)
442 ERR("PARENT ERROR: slave != ev->exe\n");
449 if (!_write_safe(STDERR_FILENO, sdata, ssize))
454 if (!ed->slave.bufcmd)
457 n = _ethumbd_slave_alloc_cmd(ed, ssize, sdata);
465 bdata = ed->slave.bufcmd + ed->slave.pcmd;
466 nbytes = ed->slave.scmd - ed->slave.pcmd;
467 nbytes = ssize < nbytes ? ssize : nbytes;
468 memcpy(bdata, sdata, nbytes);
471 ed->slave.pcmd += nbytes;
473 if (ed->slave.pcmd == ed->slave.scmd)
474 _ethumbd_slave_cmd_ready(ed);
482 _ethumbd_slave_del_cb(void *data, int type, void *event)
484 struct _Ethumbd *ed = data;
485 Ecore_Exe_Event_Del *ev = event;
488 if (ev->exe != ed->slave.exe)
492 ERR("slave exited with code: %d\n", ev->exit_code);
493 else if (ev->signalled)
494 ERR("slave exited by signal: %d\n", ev->exit_signal);
499 i = ed->queue.current;
500 ERR("failed to generate thumbnail for: \"%s:%s\"\n",
501 ed->processing->file, ed->processing->key);
503 if (ed->queue.table[i].used)
504 _ethumb_dbus_generated_signal
505 (ed, &ed->processing->id, NULL, NULL, EINA_FALSE);
506 eina_stringshare_del(ed->processing->file);
507 eina_stringshare_del(ed->processing->key);
508 eina_stringshare_del(ed->processing->thumb);
509 eina_stringshare_del(ed->processing->thumb_key);
510 free(ed->processing);
511 ed->processing = NULL;
514 ed->slave.exe = NULL;
515 if (ed->slave.bufcmd)
516 free(ed->slave.bufcmd);
518 return _ethumbd_slave_spawn(ed);
522 _ethumbd_pipe_write_setup(struct _Ethumbd *ed, int type, const void *data)
525 const float *f_value;
527 _ethumbd_write_safe(ed, &type, sizeof(type));
534 case ETHUMBD_QUALITY:
535 case ETHUMBD_COMPRESS:
538 case ETHUMBD_DOCUMENT_PAGE:
539 case ETHUMBD_VIDEO_NTIMES:
540 case ETHUMBD_VIDEO_FPS:
542 _ethumbd_write_safe(ed, i_value, sizeof(*i_value));
546 case ETHUMBD_VIDEO_TIME:
547 case ETHUMBD_VIDEO_START:
548 case ETHUMBD_VIDEO_INTERVAL:
550 _ethumbd_write_safe(ed, f_value, sizeof(*f_value));
552 case ETHUMBD_DIRECTORY:
553 case ETHUMBD_CATEGORY:
554 case ETHUMBD_FRAME_FILE:
555 case ETHUMBD_FRAME_GROUP:
556 case ETHUMBD_FRAME_SWALLOW:
557 _ethumbd_pipe_str_write(ed, data);
559 case ETHUMBD_SETUP_FINISHED:
562 ERR("wrong ethumb setup parameter.\n");
567 _process_setup(struct _Ethumbd *ed)
569 int op_id = ETHUMBD_OP_SETUP;
570 int index = ed->queue.current;
572 struct _Ethumb_Setup *setup = &ed->processing->setup;
574 _ethumbd_write_safe(ed, &op_id, sizeof(op_id));
575 _ethumbd_write_safe(ed, &index, sizeof(index));
577 if (setup->flags.fdo)
578 _ethumbd_pipe_write_setup(ed, ETHUMBD_FDO, &setup->fdo);
579 if (setup->flags.size)
581 _ethumbd_pipe_write_setup(ed, ETHUMBD_SIZE_W, &setup->tw);
582 _ethumbd_pipe_write_setup(ed, ETHUMBD_SIZE_H, &setup->th);
584 if (setup->flags.format)
585 _ethumbd_pipe_write_setup(ed, ETHUMBD_FORMAT, &setup->format);
586 if (setup->flags.aspect)
587 _ethumbd_pipe_write_setup(ed, ETHUMBD_ASPECT, &setup->aspect);
588 if (setup->flags.crop)
590 _ethumbd_pipe_write_setup(ed, ETHUMBD_CROP_X, &setup->cx);
591 _ethumbd_pipe_write_setup(ed, ETHUMBD_CROP_Y, &setup->cy);
593 if (setup->flags.quality)
594 _ethumbd_pipe_write_setup(ed, ETHUMBD_QUALITY, &setup->quality);
595 if (setup->flags.compress)
596 _ethumbd_pipe_write_setup(ed, ETHUMBD_COMPRESS, &setup->compress);
597 if (setup->flags.directory)
598 _ethumbd_pipe_write_setup(ed, ETHUMBD_DIRECTORY, setup->directory);
599 if (setup->flags.category)
600 _ethumbd_pipe_write_setup(ed, ETHUMBD_CATEGORY, setup->category);
601 if (setup->flags.frame)
603 _ethumbd_pipe_write_setup(ed, ETHUMBD_FRAME_FILE, setup->theme_file);
604 _ethumbd_pipe_write_setup(ed, ETHUMBD_FRAME_GROUP, setup->group);
605 _ethumbd_pipe_write_setup(ed, ETHUMBD_FRAME_SWALLOW, setup->swallow);
607 if (setup->flags.video_time)
608 _ethumbd_pipe_write_setup(ed, ETHUMBD_VIDEO_TIME, &setup->video_time);
609 if (setup->flags.video_start)
610 _ethumbd_pipe_write_setup(ed, ETHUMBD_VIDEO_START, &setup->video_start);
611 if (setup->flags.video_interval)
612 _ethumbd_pipe_write_setup(ed, ETHUMBD_VIDEO_INTERVAL,
613 &setup->video_interval);
614 if (setup->flags.video_ntimes)
615 _ethumbd_pipe_write_setup(ed, ETHUMBD_VIDEO_NTIMES, &setup->video_ntimes);
616 if (setup->flags.video_fps)
617 _ethumbd_pipe_write_setup(ed, ETHUMBD_VIDEO_FPS, &setup->video_fps);
618 if (setup->flags.document_page)
619 _ethumbd_pipe_write_setup(ed, ETHUMBD_DOCUMENT_PAGE,
620 &setup->document_page);
621 _ethumbd_pipe_write_setup(ed, ETHUMBD_SETUP_FINISHED, NULL);
624 if (setup->directory) eina_stringshare_del(setup->directory);
625 if (setup->category) eina_stringshare_del(setup->category);
626 if (setup->theme_file) eina_stringshare_del(setup->theme_file);
627 if (setup->group) eina_stringshare_del(setup->group);
628 if (setup->swallow) eina_stringshare_del(setup->swallow);
630 free(ed->processing);
631 ed->processing = NULL;
635 _process_file(struct _Ethumbd *ed)
637 _ethumbd_child_write_op_generate
638 (ed, ed->queue.current, ed->processing->file,
639 ed->processing->key, ed->processing->thumb, ed->processing->thumb_key);
643 _get_next_on_queue(struct _Ethumb_Queue *queue)
646 struct _Ethumb_Object *eobject;
650 if (i >= queue->count)
653 index = queue->list[i];
654 eobject = &(queue->table[index]);
655 while (!eobject->nqueue)
657 i = (i + 1) % queue->count;
659 index = queue->list[i];
660 eobject = &(queue->table[index]);
663 return queue->list[i];
667 _process_queue_cb(void *data)
669 struct _Ethumb_Object *eobject;
671 struct _Ethumbd *ed = data;
672 struct _Ethumb_Queue *queue = &ed->queue;
673 struct _Ethumb_Request *request;
682 _ethumbd_timeout_start(ed);
687 i = _get_next_on_queue(queue);
688 eobject = &(queue->table[i]);
690 request = eina_list_data_get(eobject->queue);
691 eobject->queue = eina_list_remove_list(eobject->queue, eobject->queue);
692 ed->queue.current = i;
693 DBG("processing file: \"%s:%s\"...\n", request->file,
695 ed->processing = request;
702 _ethumb_dbus_inc_min_id(eobject);
713 _process_queue_start(struct _Ethumbd *ed)
716 ed->idler = ecore_idler_add(_process_queue_cb, ed);
720 _process_queue_stop(struct _Ethumbd *ed)
724 ecore_idler_del(ed->idler);
730 _ethumb_table_append(struct _Ethumbd *ed)
734 struct _Ethumb_Queue *q = &ed->queue;
736 if (q->count == q->max_count)
738 int new_max = q->max_count + 5;
742 start = q->max_count;
743 size = new_max - q->max_count;
745 tmp = realloc(q->table, new_max * sizeof(struct _Ethumb_Object));
748 CRIT("could not realloc q->table to %zd bytes: %s",
749 new_max * sizeof(struct _Ethumb_Object), strerror(errno));
753 memset(&q->table[start], 0, size * sizeof(struct _Ethumb_Object));
755 tmp = realloc(q->list, new_max * sizeof(int));
758 CRIT("could not realloc q->list to %zd bytes: %s",
759 new_max * sizeof(int), strerror(errno));
764 q->max_count = new_max;
767 for (i = 0; i < q->max_count; i++)
769 if (!q->table[i].used)
773 snprintf(buf, sizeof(buf), "%s/%d", _ethumb_dbus_path, i);
774 q->table[i].used = 1;
775 q->table[i].path = eina_stringshare_add(buf);
776 q->table[i].max_id = -1;
777 q->table[i].min_id = -1;
778 q->list[q->count] = i;
780 DBG("new object: %s, index = %d, count = %d\n", buf, i, q->count);
786 _get_index_for_path(const char *path)
790 n = sscanf(path, "/org/enlightenment/Ethumb/%d", &i);
797 _ethumb_table_del(struct _Ethumbd *ed, int i)
802 struct _Ethumb_Queue *q = &ed->queue;
803 struct _Ethumb_Object_Data *odata;
805 eina_stringshare_del(q->table[i].path);
807 l = q->table[i].queue;
810 struct _Ethumb_Request *request = l->data;
811 eina_stringshare_del(request->file);
812 eina_stringshare_del(request->key);
813 eina_stringshare_del(request->thumb);
814 eina_stringshare_del(request->thumb_key);
816 l = eina_list_remove_list(l, l);
818 q->nqueue -= q->table[i].nqueue;
820 il = e_dbus_object_interfaces_get(q->table[i].dbus_obj);
823 e_dbus_object_interface_detach(q->table[i].dbus_obj, il->data);
824 il = e_dbus_object_interfaces_get(q->table[i].dbus_obj);
826 odata = e_dbus_object_data_get(q->table[i].dbus_obj);
828 e_dbus_object_free(q->table[i].dbus_obj);
830 memset(&(q->table[i]), 0, sizeof(struct _Ethumb_Object));
831 for (j = 0; j < q->count; j++)
834 q->list[j] = q->list[q->count - 1];
838 _ethumbd_child_write_op_del(ed, i);
839 if (!q->count && !ed->processing)
840 _ethumbd_timeout_start(ed);
844 _ethumb_table_clear(struct _Ethumbd *ed)
848 for (i = 0; i < ed->queue.max_count; i++)
849 if (ed->queue.table[i].used)
850 _ethumb_table_del(ed, i);
854 _name_owner_changed_cb(void *data, DBusMessage *msg)
857 struct _Ethumbd *ed = data;
858 struct _Ethumb_Queue *q = &ed->queue;
859 const char *name, *from, *to;
862 dbus_error_init(&err);
863 if (!dbus_message_get_args(msg, &err,
864 DBUS_TYPE_STRING, &name,
865 DBUS_TYPE_STRING, &from,
866 DBUS_TYPE_STRING, &to,
869 ERR("could not get NameOwnerChanged arguments: %s: %s\n",
870 err.name, err.message);
871 dbus_error_free(&err);
875 DBG("NameOwnerChanged: name = %s, from = %s, to = %s\n", name, from, to);
877 if (from[0] == '\0' || to[0] != '\0')
880 from = eina_stringshare_add(from);
881 for (i = 0; i < q->max_count; i++)
883 if (q->table[i].used && q->table[i].client == from)
885 _ethumb_table_del(ed, i);
886 DBG("deleting [%d] from queue table.\n", i);
892 _ethumb_dbus_add_name_owner_changed_cb(struct _Ethumbd *ed)
894 ed->name_owner_changed_handler = e_dbus_signal_handler_add
895 (ed->conn, fdo_bus_name, fdo_path, fdo_interface, "NameOwnerChanged",
896 _name_owner_changed_cb, ed);
900 _ethumb_dbus_ethumb_new_cb(E_DBus_Object *object, DBusMessage *msg)
903 DBusMessageIter iter;
904 E_DBus_Object *dbus_object;
905 struct _Ethumb_Object_Data *odata;
907 const char *return_path = "";
911 ed = e_dbus_object_data_get(object);
912 client = dbus_message_get_sender(msg);
916 i = _ethumb_table_append(ed);
920 odata = calloc(1, sizeof(*odata));
924 ed->queue.table[i].client = eina_stringshare_add(client);
925 return_path = ed->queue.table[i].path;
927 dbus_object = e_dbus_object_add(ed->conn, return_path, odata);
930 ERR("could not create dbus_object.\n");
936 e_dbus_object_interface_attach(dbus_object, ed->objects_iface);
937 ed->queue.table[i].dbus_obj = dbus_object;
939 _ethumbd_child_write_op_new(ed, i);
940 _ethumbd_timeout_stop(ed);
943 reply = dbus_message_new_method_return(msg);
944 dbus_message_iter_init_append(reply, &iter);
945 dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
950 static struct _Ethumb_DBus_Method_Table _ethumb_dbus_methods[] =
952 {"new", "", "o", _ethumb_dbus_ethumb_new_cb},
953 {NULL, NULL, NULL, NULL}
957 _ethumb_dbus_get_bytearray(DBusMessageIter *iter)
961 DBusMessageIter riter;
964 el_type = dbus_message_iter_get_element_type(iter);
965 if (el_type != DBUS_TYPE_BYTE)
967 ERR("not an byte array element.\n");
971 dbus_message_iter_recurse(iter, &riter);
972 dbus_message_iter_get_fixed_array(&riter, &result, &length);
974 if ((length == 0) || (result[0] == '\0'))
977 return eina_stringshare_add_length(result, length);
981 _ethumb_dbus_append_bytearray(DBusMessageIter *iter, const char *string)
983 DBusMessageIter viter;
988 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &viter);
989 dbus_message_iter_append_fixed_array
990 (&viter, DBUS_TYPE_BYTE, &string, strlen(string) + 1);
991 dbus_message_iter_close_container(iter, &viter);
995 _ethumb_dbus_queue_add_cb(E_DBus_Object *object, DBusMessage *msg)
998 DBusMessageIter iter;
999 const char *file, *key;
1000 const char *thumb, *thumb_key;
1001 struct _Ethumb_Object_Data *odata;
1002 struct _Ethumb_Object *eobject;
1003 struct _Ethumbd *ed;
1004 struct _Ethumb_Request *request;
1005 dbus_int32_t id = -1;
1007 dbus_message_iter_init(msg, &iter);
1008 dbus_message_iter_get_basic(&iter, &id);
1009 dbus_message_iter_next(&iter);
1010 file = _ethumb_dbus_get_bytearray(&iter);
1011 dbus_message_iter_next(&iter);
1012 key = _ethumb_dbus_get_bytearray(&iter);
1013 dbus_message_iter_next(&iter);
1014 thumb = _ethumb_dbus_get_bytearray(&iter);
1015 dbus_message_iter_next(&iter);
1016 thumb_key = _ethumb_dbus_get_bytearray(&iter);
1020 ERR("no filename given.\n");
1024 odata = e_dbus_object_data_get(object);
1027 ERR("could not get dbus_object data.\n");
1032 eobject = &(ed->queue.table[odata->index]);
1033 if (!_ethumb_dbus_check_id(eobject, id))
1035 request = calloc(1, sizeof(*request));
1037 request->file = file;
1039 request->thumb = thumb;
1040 request->thumb_key = thumb_key;
1041 eobject->queue = eina_list_append(eobject->queue, request);
1044 _ethumb_dbus_inc_max_id(eobject, id);
1046 _process_queue_start(ed);
1049 reply = dbus_message_new_method_return(msg);
1050 dbus_message_iter_init_append(reply, &iter);
1051 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &id);
1056 _ethumb_dbus_queue_remove_cb(E_DBus_Object *object, DBusMessage *msg)
1059 DBusMessageIter iter;
1061 struct _Ethumb_Object_Data *odata;
1062 struct _Ethumb_Object *eobject;
1063 struct _Ethumb_Request *request;
1064 struct _Ethumbd *ed;
1068 dbus_message_iter_init(msg, &iter);
1069 dbus_message_iter_get_basic(&iter, &id);
1071 odata = e_dbus_object_data_get(object);
1074 ERR("could not get dbus_object data.\n");
1079 eobject = &ed->queue.table[odata->index];
1084 if (id == request->id)
1092 eina_stringshare_del(request->file);
1093 eina_stringshare_del(request->key);
1094 eina_stringshare_del(request->thumb);
1095 eina_stringshare_del(request->thumb_key);
1097 eobject->queue = eina_list_remove_list(eobject->queue, l);
1100 _ethumb_dbus_inc_min_id(eobject);
1104 reply = dbus_message_new_method_return(msg);
1105 dbus_message_iter_init_append(reply, &iter);
1106 dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &r);
1111 _ethumb_dbus_queue_clear_cb(E_DBus_Object *object, DBusMessage *msg)
1114 struct _Ethumb_Object_Data *odata;
1115 struct _Ethumb_Object *eobject;
1116 struct _Ethumbd *ed;
1119 odata = e_dbus_object_data_get(object);
1122 ERR("could not get dbus_object data.\n");
1127 eobject = &ed->queue.table[odata->index];
1131 struct _Ethumb_Request *request = l->data;
1132 eina_stringshare_del(request->file);
1133 eina_stringshare_del(request->key);
1134 eina_stringshare_del(request->thumb);
1135 eina_stringshare_del(request->thumb_key);
1137 l = eina_list_remove_list(l, l);
1139 ed->queue.nqueue -= eobject->nqueue;
1140 eobject->nqueue = 0;
1143 reply = dbus_message_new_method_return(msg);
1148 _ethumb_dbus_delete_cb(E_DBus_Object *object, DBusMessage *msg)
1151 DBusMessageIter iter;
1152 struct _Ethumb_Object_Data *odata;
1153 struct _Ethumbd *ed;
1155 dbus_message_iter_init(msg, &iter);
1156 reply = dbus_message_new_method_return(msg);
1158 odata = e_dbus_object_data_get(object);
1161 ERR("could not get dbus_object data for del_cb.\n");
1165 _ethumb_table_del(ed, odata->index);
1172 _ethumb_dbus_fdo_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request __UNUSED__)
1177 type = dbus_message_iter_get_arg_type(iter);
1178 if (type != DBUS_TYPE_INT32)
1180 ERR("invalid param for fdo_set.\n");
1184 dbus_message_iter_get_basic(iter, &fdo);
1185 DBG("setting fdo to: %d\n", fdo);
1191 _ethumb_dbus_size_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 size_set.\n");
1204 dbus_message_iter_recurse(iter, &oiter);
1205 dbus_message_iter_get_basic(&oiter, &w);
1206 dbus_message_iter_next(&oiter);
1207 dbus_message_iter_get_basic(&oiter, &h);
1208 DBG("setting size to: %dx%d\n", w, h);
1209 request->setup.flags.size = 1;
1210 request->setup.tw = w;
1211 request->setup.th = h;
1217 _ethumb_dbus_format_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1220 dbus_int32_t format;
1222 type = dbus_message_iter_get_arg_type(iter);
1223 if (type != DBUS_TYPE_INT32)
1225 ERR("invalid param for format_set.\n");
1229 dbus_message_iter_get_basic(iter, &format);
1230 DBG("setting format to: %d\n", format);
1231 request->setup.flags.format = 1;
1232 request->setup.format = format;
1238 _ethumb_dbus_aspect_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1241 dbus_int32_t aspect;
1243 type = dbus_message_iter_get_arg_type(iter);
1244 if (type != DBUS_TYPE_INT32)
1246 ERR("invalid param for aspect_set.\n");
1250 dbus_message_iter_get_basic(iter, &aspect);
1251 DBG("setting aspect to: %d\n", aspect);
1252 request->setup.flags.aspect = 1;
1253 request->setup.aspect = aspect;
1259 _ethumb_dbus_crop_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1261 DBusMessageIter oiter;
1265 type = dbus_message_iter_get_arg_type(iter);
1266 if (type != DBUS_TYPE_STRUCT)
1268 ERR("invalid param for crop_set.\n");
1272 dbus_message_iter_recurse(iter, &oiter);
1273 dbus_message_iter_get_basic(&oiter, &x);
1274 dbus_message_iter_next(&oiter);
1275 dbus_message_iter_get_basic(&oiter, &y);
1276 DBG("setting crop to: %3.2f,%3.2f\n", x, y);
1277 request->setup.flags.crop = 1;
1278 request->setup.cx = x;
1279 request->setup.cy = y;
1285 _ethumb_dbus_quality_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1288 dbus_int32_t quality;
1290 type = dbus_message_iter_get_arg_type(iter);
1291 if (type != DBUS_TYPE_INT32)
1293 ERR("invalid param for quality_set.\n");
1297 dbus_message_iter_get_basic(iter, &quality);
1298 DBG("setting quality to: %d\n", quality);
1299 request->setup.flags.quality = 1;
1300 request->setup.quality = quality;
1307 _ethumb_dbus_compress_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1310 dbus_int32_t compress;
1312 type = dbus_message_iter_get_arg_type(iter);
1313 if (type != DBUS_TYPE_INT32)
1315 ERR("invalid param for compress_set.\n");
1319 dbus_message_iter_get_basic(iter, &compress);
1320 DBG("setting compress to: %d\n", compress);
1321 request->setup.flags.compress = 1;
1322 request->setup.compress = compress;
1328 _ethumb_dbus_frame_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1330 DBusMessageIter oiter;
1332 const char *file, *group, *swallow;
1334 type = dbus_message_iter_get_arg_type(iter);
1335 if (type != DBUS_TYPE_STRUCT)
1337 ERR("invalid param for frame_set.\n");
1341 dbus_message_iter_recurse(iter, &oiter);
1342 file = _ethumb_dbus_get_bytearray(&oiter);
1343 dbus_message_iter_next(&oiter);
1344 group = _ethumb_dbus_get_bytearray(&oiter);
1345 dbus_message_iter_next(&oiter);
1346 swallow = _ethumb_dbus_get_bytearray(&oiter);
1347 DBG("setting frame to \"%s:%s:%s\"\n", file, group, swallow);
1348 request->setup.flags.frame = 1;
1349 request->setup.theme_file = eina_stringshare_add(file);
1350 request->setup.group = eina_stringshare_add(group);
1351 request->setup.swallow = eina_stringshare_add(swallow);
1357 _ethumb_dbus_directory_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1360 const char *directory;
1362 type = dbus_message_iter_get_arg_type(iter);
1363 if (type != DBUS_TYPE_ARRAY)
1365 ERR("invalid param for dir_path_set.\n");
1369 directory = _ethumb_dbus_get_bytearray(iter);
1370 DBG("setting directory to: %s\n", directory);
1371 request->setup.flags.directory = 1;
1372 request->setup.directory = eina_stringshare_add(directory);
1378 _ethumb_dbus_category_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1381 const char *category;
1383 type = dbus_message_iter_get_arg_type(iter);
1384 if (type != DBUS_TYPE_ARRAY)
1386 ERR("invalid param for category.\n");
1390 category = _ethumb_dbus_get_bytearray(iter);
1391 DBG("setting category to: %s\n", category);
1392 request->setup.flags.category = 1;
1393 request->setup.category = eina_stringshare_add(category);
1399 _ethumb_dbus_video_time_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1404 type = dbus_message_iter_get_arg_type(iter);
1405 if (type != DBUS_TYPE_DOUBLE)
1407 ERR("invalid param for video_time_set.\n");
1411 dbus_message_iter_get_basic(iter, &video_time);
1412 DBG("setting video_time to: %3.2f\n", video_time);
1413 request->setup.flags.video_time = 1;
1414 request->setup.video_time = video_time;
1420 _ethumb_dbus_video_start_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1425 type = dbus_message_iter_get_arg_type(iter);
1426 if (type != DBUS_TYPE_DOUBLE)
1428 ERR("invalid param for video_start_set.\n");
1432 dbus_message_iter_get_basic(iter, &video_start);
1433 DBG("setting video_start to: %3.2f\n", video_start);
1434 request->setup.flags.video_start = 1;
1435 request->setup.video_start = video_start;
1441 _ethumb_dbus_video_interval_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1444 double video_interval;
1446 type = dbus_message_iter_get_arg_type(iter);
1447 if (type != DBUS_TYPE_DOUBLE)
1449 ERR("invalid param for video_interval_set.\n");
1453 dbus_message_iter_get_basic(iter, &video_interval);
1454 DBG("setting video_interval to: %3.2f\n", video_interval);
1455 request->setup.flags.video_interval = 1;
1456 request->setup.video_interval = video_interval;
1462 _ethumb_dbus_video_ntimes_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1465 unsigned int video_ntimes;
1467 type = dbus_message_iter_get_arg_type(iter);
1468 if (type != DBUS_TYPE_UINT32)
1470 ERR("invalid param for video_ntimes_set.\n");
1474 dbus_message_iter_get_basic(iter, &video_ntimes);
1475 DBG("setting video_ntimes to: %3.2d\n", video_ntimes);
1476 request->setup.flags.video_ntimes = 1;
1477 request->setup.video_ntimes = video_ntimes;
1483 _ethumb_dbus_video_fps_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1486 unsigned int video_fps;
1488 type = dbus_message_iter_get_arg_type(iter);
1489 if (type != DBUS_TYPE_UINT32)
1491 ERR("invalid param for video_fps_set.\n");
1495 dbus_message_iter_get_basic(iter, &video_fps);
1496 DBG("setting video_fps to: %3.2d\n", video_fps);
1497 request->setup.flags.video_fps = 1;
1498 request->setup.video_fps = video_fps;
1504 _ethumb_dbus_document_page_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1507 unsigned int document_page;
1509 type = dbus_message_iter_get_arg_type(iter);
1510 if (type != DBUS_TYPE_UINT32)
1512 ERR("invalid param for document_page_set.\n");
1516 dbus_message_iter_get_basic(iter, &document_page);
1517 DBG("setting document_page to: %d\n", document_page);
1518 request->setup.flags.document_page = 1;
1519 request->setup.document_page = document_page;
1527 int (*setup_func)(struct _Ethumb_Object *eobject, DBusMessageIter *iter, struct _Ethumb_Request *request);
1529 {"fdo", _ethumb_dbus_fdo_set},
1530 {"size", _ethumb_dbus_size_set},
1531 {"format", _ethumb_dbus_format_set},
1532 {"aspect", _ethumb_dbus_aspect_set},
1533 {"crop", _ethumb_dbus_crop_set},
1534 {"quality", _ethumb_dbus_quality_set},
1535 {"compress", _ethumb_dbus_compress_set},
1536 {"frame", _ethumb_dbus_frame_set},
1537 {"directory", _ethumb_dbus_directory_set},
1538 {"category", _ethumb_dbus_category_set},
1539 {"video_time", _ethumb_dbus_video_time_set},
1540 {"video_start", _ethumb_dbus_video_start_set},
1541 {"video_interval", _ethumb_dbus_video_interval_set},
1542 {"video_ntimes", _ethumb_dbus_video_ntimes_set},
1543 {"video_fps", _ethumb_dbus_video_fps_set},
1544 {"document_page", _ethumb_dbus_document_page_set},
1549 _ethumb_dbus_ethumb_setup_parse_element(struct _Ethumb_Object *eobject, DBusMessageIter *iter, struct _Ethumb_Request *request)
1551 DBusMessageIter viter, diter;
1555 dbus_message_iter_recurse(iter, &diter);
1556 dbus_message_iter_get_basic(&diter, &option);
1557 dbus_message_iter_next(&diter);
1560 for (i = 0; _option_cbs[i].option; i++)
1561 if (!strcmp(_option_cbs[i].option, option))
1569 ERR("ethumb_setup invalid option: %s\n", option);
1573 dbus_message_iter_recurse(&diter, &viter);
1574 return _option_cbs[i].setup_func(eobject, &viter, request);
1578 _ethumb_dbus_ethumb_setup_cb(E_DBus_Object *object, DBusMessage *msg)
1581 DBusMessageIter iter, aiter;
1582 struct _Ethumb_Object_Data *odata;
1583 struct _Ethumbd *ed;
1584 struct _Ethumb_Object *eobject;
1585 struct _Ethumb_Request *request;
1589 dbus_message_iter_init(msg, &iter);
1590 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1592 ERR("wrong parameters.\n");
1596 odata = e_dbus_object_data_get(object);
1599 ERR("could not get dbus_object data for setup_cb.\n");
1604 eobject = &ed->queue.table[odata->index];
1606 request = calloc(1, sizeof(*request));
1608 dbus_message_iter_recurse(&iter, &aiter);
1609 atype = dbus_message_iter_get_arg_type(&aiter);
1612 while (atype != DBUS_TYPE_INVALID)
1614 if (!_ethumb_dbus_ethumb_setup_parse_element(eobject, &aiter, request))
1616 dbus_message_iter_next(&aiter);
1617 atype = dbus_message_iter_get_arg_type(&aiter);
1620 eobject->queue = eina_list_append(eobject->queue, request);
1625 reply = dbus_message_new_method_return(msg);
1626 dbus_message_iter_init_append(reply, &iter);
1627 dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &r);
1633 _ethumb_dbus_generated_signal(struct _Ethumbd *ed, int *id, const char *thumb_path, const char *thumb_key, Eina_Bool success)
1635 DBusMessage *signal;
1638 DBusMessageIter iter;
1645 current = ed->queue.current;
1646 opath = ed->queue.table[current].path;
1647 signal = dbus_message_new_signal
1648 (opath, _ethumb_dbus_objects_interface, "generated");
1650 dbus_message_iter_init_append(signal, &iter);
1651 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &id32);
1652 _ethumb_dbus_append_bytearray(&iter, thumb_path);
1653 _ethumb_dbus_append_bytearray(&iter, thumb_key);
1654 dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &value);
1656 e_dbus_message_send(ed->conn, signal, NULL, -1, NULL);
1657 dbus_message_unref(signal);
1660 static struct _Ethumb_DBus_Method_Table _ethumb_dbus_objects_methods[] = {
1661 {"queue_add", "iayayayay", "i", _ethumb_dbus_queue_add_cb},
1662 {"queue_remove", "i", "b", _ethumb_dbus_queue_remove_cb},
1663 {"clear_queue", "", "", _ethumb_dbus_queue_clear_cb},
1664 {"ethumb_setup", "a{sv}", "b", _ethumb_dbus_ethumb_setup_cb},
1665 {"delete", "", "", _ethumb_dbus_delete_cb},
1666 {NULL, NULL, NULL, NULL}
1669 static struct _Ethumb_DBus_Signal_Table _ethumb_dbus_objects_signals[] = {
1670 {"generated", "iayayb"},
1675 _ethumb_dbus_interface_elements_add(E_DBus_Interface *iface, struct _Ethumb_DBus_Method_Table *mtable, struct _Ethumb_DBus_Signal_Table *stable)
1678 while (mtable && mtable[++i].name != NULL)
1679 if (!e_dbus_interface_method_add(iface,
1681 mtable[i].signature,
1683 mtable[i].function))
1687 while (stable && stable[++i].name != NULL)
1688 if (!e_dbus_interface_signal_add(iface,
1690 stable[i].signature))
1696 _ethumb_dbus_request_name_cb(void *data, DBusMessage *msg __UNUSED__, DBusError *err)
1698 E_DBus_Object *dbus_object;
1699 struct _Ethumbd *ed = data;
1702 if (dbus_error_is_set(err))
1704 ERR("request name error: %s\n", err->message);
1705 dbus_error_free(err);
1706 e_dbus_connection_close(ed->conn);
1710 dbus_object = e_dbus_object_add(ed->conn, _ethumb_dbus_path, ed);
1713 ed->dbus_obj = dbus_object;
1714 ed->eiface = e_dbus_interface_new(_ethumb_dbus_interface);
1717 ERR("could not create interface.\n");
1720 r = _ethumb_dbus_interface_elements_add(ed->eiface,
1721 _ethumb_dbus_methods, NULL);
1724 ERR("could not add methods to the interface.\n");
1725 e_dbus_interface_unref(ed->eiface);
1728 e_dbus_object_interface_attach(dbus_object, ed->eiface);
1730 ed->objects_iface = e_dbus_interface_new(_ethumb_dbus_objects_interface);
1731 if (!ed->objects_iface)
1733 ERR("could not create interface.\n");
1737 r = _ethumb_dbus_interface_elements_add(ed->objects_iface,
1738 _ethumb_dbus_objects_methods,
1739 _ethumb_dbus_objects_signals);
1742 ERR("ERROR: could not setup objects interface methods.\n");
1743 e_dbus_interface_unref(ed->objects_iface);
1747 _ethumb_dbus_add_name_owner_changed_cb(ed);
1749 _ethumbd_timeout_start(ed);
1753 _ethumb_dbus_setup(struct _Ethumbd *ed)
1756 (ed->conn, _ethumb_dbus_bus_name, 0, _ethumb_dbus_request_name_cb, ed);
1762 _ethumb_dbus_finish(struct _Ethumbd *ed)
1764 _process_queue_stop(ed);
1765 _ethumb_table_clear(ed);
1766 e_dbus_signal_handler_del(ed->conn, ed->name_owner_changed_handler);
1767 e_dbus_interface_unref(ed->objects_iface);
1768 e_dbus_interface_unref(ed->eiface);
1769 e_dbus_object_free(ed->dbus_obj);
1770 free(ed->queue.table);
1771 free(ed->queue.list);
1775 _ethumbd_slave_spawn(struct _Ethumbd *ed)
1777 ed->slave.data_cb = ecore_event_handler_add(
1778 ECORE_EXE_EVENT_DATA, _ethumbd_slave_data_read_cb, ed);
1779 ed->slave.del_cb = ecore_event_handler_add(
1780 ECORE_EXE_EVENT_DEL, _ethumbd_slave_del_cb, ed);
1782 ed->slave.bufcmd = NULL;
1785 ed->slave.exe = ecore_exe_pipe_run(
1786 ETHUMB_LIBEXEC_DIR"/ethumbd_slave",
1787 ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE, ed);
1790 ERR("could not create slave.\n");
1798 main(int argc, char *argv[])
1800 Eina_Bool quit_option = 0;
1805 double timeout = -1;
1807 memset(&ed, 0, sizeof(ed));
1813 child = _ethumbd_slave_spawn(&ed);
1828 ERR("could not init e_dbus.\n");
1833 Ecore_Getopt_Value values[] = {
1834 ECORE_GETOPT_VALUE_DOUBLE(timeout),
1835 ECORE_GETOPT_VALUE_BOOL(quit_option),
1836 ECORE_GETOPT_VALUE_BOOL(quit_option),
1837 ECORE_GETOPT_VALUE_BOOL(quit_option),
1838 ECORE_GETOPT_VALUE_BOOL(quit_option),
1839 ECORE_GETOPT_VALUE_NONE
1842 arg_index = ecore_getopt_parse(&optdesc, values, argc, argv);
1845 ERR("Could not parse arguments.\n");
1853 ed.conn = e_dbus_bus_get(DBUS_BUS_SESSION);
1856 ERR("could not connect to session bus.\n");
1861 ed.timeout = timeout;
1863 if (!_ethumb_dbus_setup(&ed))
1865 e_dbus_connection_close(ed.conn);
1866 ERR("could not setup dbus connection.\n");
1871 ecore_main_loop_begin();
1872 _ethumb_dbus_finish(&ed);
1878 ecore_exe_quit(ed.slave.exe);