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_DOM_DBG(_log_domain, __VA_ARGS__)
48 #define INF(...) EINA_LOG_DOM_INFO(_log_domain, __VA_ARGS__)
49 #define WRN(...) EINA_LOG_DOM_WARN(_log_domain, __VA_ARGS__)
50 #define ERR(...) EINA_LOG_DOM_ERR(_log_domain, __VA_ARGS__)
51 #define CRIT(...) EINA_LOG_DOM_CRIT(_log_domain, __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";
61 static int _log_domain = -1;
72 Eina_Bool quality : 1;
73 Eina_Bool compress : 1;
74 Eina_Bool directory : 1;
75 Eina_Bool category : 1;
77 Eina_Bool video_time : 1;
78 Eina_Bool video_start : 1;
79 Eina_Bool video_interval : 1;
80 Eina_Bool video_ntimes : 1;
81 Eina_Bool video_fps : 1;
82 Eina_Bool document_page : 1;
91 const char *directory;
93 const char *theme_file;
99 unsigned int video_ntimes;
100 unsigned int video_fps;
101 unsigned int document_page;
104 struct _Ethumb_Request
107 const char *file, *key;
108 const char *thumb, *thumb_key;
109 struct _Ethumb_Setup setup;
112 struct _Ethumb_Object
122 E_DBus_Object *dbus_obj;
132 struct _Ethumb_Object *table;
139 Ecore_Event_Handler *data_cb;
140 Ecore_Event_Handler *del_cb;
141 char *bufcmd; // buffer to read commands from slave
142 int scmd; // size of command to read
143 int pcmd; // position in the command buffer
148 E_DBus_Connection *conn;
149 E_DBus_Signal_Handler *name_owner_changed_handler;
150 E_DBus_Interface *eiface, *objects_iface;
151 E_DBus_Object *dbus_obj;
153 struct _Ethumb_Request *processing;
154 struct _Ethumb_Queue queue;
156 Ecore_Timer *timeout_timer;
157 struct _Ethumb_Slave slave;
160 struct _Ethumb_Object_Data
166 struct _Ethumb_DBus_Method_Table
169 const char *signature;
171 E_DBus_Method_Cb function;
174 struct _Ethumb_DBus_Signal_Table
177 const char *signature;
180 const Ecore_Getopt optdesc = {
184 "(C) 2009 - ProFUSION embedded systems",
185 "LGPL v3 - GNU Lesser General Public License",
188 "ethumbd uses the Ethumb library to create thumbnails for any "
189 "program that requests it (now just by dbus).\n",
192 ECORE_GETOPT_STORE_DOUBLE
193 ('t', "timeout", "finish ethumbd after <timeout> seconds of no activity."),
194 ECORE_GETOPT_LICENSE('L', "license"),
195 ECORE_GETOPT_COPYRIGHT('C', "copyright"),
196 ECORE_GETOPT_VERSION('V', "version"),
197 ECORE_GETOPT_HELP('h', "help"),
198 ECORE_GETOPT_SENTINEL
202 static void _ethumb_dbus_generated_signal(struct _Ethumbd *ed, int *id, const char *thumb_path, const char *thumb_key, Eina_Bool success);
203 static int _ethumbd_slave_spawn(struct _Ethumbd *ed);
206 _ethumbd_timeout_cb(void *data)
208 struct _Ethumbd *ed = data;
210 ecore_main_loop_quit();
211 ed->timeout_timer = NULL;
217 _ethumbd_timeout_start(struct _Ethumbd *ed)
222 if (!ed->timeout_timer)
223 ed->timeout_timer = ecore_timer_add(ed->timeout, _ethumbd_timeout_cb, ed);
227 _ethumbd_timeout_stop(struct _Ethumbd *ed)
229 if (!ed->timeout_timer)
232 ecore_timer_del(ed->timeout_timer);
233 ed->timeout_timer = NULL;
237 _ethumb_dbus_check_id(struct _Ethumb_Object *eobject, int id)
239 if (id < 0 || id > MAX_ID)
242 if (eobject->min_id < eobject->max_id)
243 return id < eobject->min_id || id > eobject->max_id;
244 else if (eobject->min_id > eobject->max_id)
245 return id < eobject->min_id && id > eobject->max_id;
247 return id != eobject->max_id;
251 _ethumb_dbus_inc_max_id(struct _Ethumb_Object *eobject, int id)
253 if (eobject->min_id < 0 && eobject->max_id < 0)
254 eobject->min_id = id;
256 eobject->max_id = id;
260 _ethumb_dbus_inc_min_id(struct _Ethumb_Object *eobject)
267 struct _Ethumb_Request *request = l->data;
268 if (request->id >= 0)
270 eobject->min_id = request->id;
279 eobject->min_id = -1;
280 eobject->max_id = -1;
285 _ethumbd_write_safe(struct _Ethumbd *ed, const void *buf, ssize_t size)
290 ERR("slave process isn't running.");
294 ecore_exe_send(ed->slave.exe, buf, size);
299 _ethumbd_child_write_op_new(struct _Ethumbd *ed, int index)
301 int id = ETHUMBD_OP_NEW;
302 _ethumbd_write_safe(ed, &id, sizeof(id));
303 _ethumbd_write_safe(ed, &index, sizeof(index));
307 _ethumbd_child_write_op_del(struct _Ethumbd *ed, int index)
309 int id = ETHUMBD_OP_DEL;
310 _ethumbd_write_safe(ed, &id, sizeof(id));
311 _ethumbd_write_safe(ed, &index, sizeof(index));
315 _ethumbd_pipe_str_write(struct _Ethumbd *ed, const char *str)
320 len = strlen(str) + 1;
324 _ethumbd_write_safe(ed, &len, sizeof(len));
325 _ethumbd_write_safe(ed, str, len);
329 _ethumbd_child_write_op_generate(struct _Ethumbd *ed, int index, const char *path, const char *key, const char *thumb_path, const char *thumb_key)
331 int id = ETHUMBD_OP_GENERATE;
333 _ethumbd_write_safe(ed, &id, sizeof(id));
334 _ethumbd_write_safe(ed, &index, sizeof(index));
336 _ethumbd_pipe_str_write(ed, path);
337 _ethumbd_pipe_str_write(ed, key);
338 _ethumbd_pipe_str_write(ed, thumb_path);
339 _ethumbd_pipe_str_write(ed, thumb_key);
343 _generated_cb(struct _Ethumbd *ed, Eina_Bool success, const char *thumb_path, const char *thumb_key)
345 int i = ed->queue.current;
347 DBG("thumbnail ready at: \"%s:%s\"", thumb_path, thumb_key);
349 if (ed->queue.table[i].used)
350 _ethumb_dbus_generated_signal
351 (ed, &ed->processing->id, thumb_path, thumb_key, success);
352 eina_stringshare_del(ed->processing->file);
353 eina_stringshare_del(ed->processing->key);
354 eina_stringshare_del(ed->processing->thumb);
355 eina_stringshare_del(ed->processing->thumb_key);
356 free(ed->processing);
357 ed->processing = NULL;
361 _write_safe(int fd, void *data, size_t size)
363 unsigned char *buf = data;
367 size_t r = write(fd, buf, todo);
373 else if ((r < 0) && (errno != EINTR))
375 ERR("could not write to fd=%d: %s", fd, strerror(errno));
383 _ethumbd_slave_cmd_ready(struct _Ethumbd *ed)
385 char *bufcmd = ed->slave.bufcmd;
387 const char *thumb_path = NULL;
388 const char *thumb_key = NULL;
389 int *size_path, *size_key;
391 success = (Eina_Bool *)bufcmd;
392 bufcmd += sizeof(*success);
394 size_path = (int *)bufcmd;
395 bufcmd += sizeof(*size_path);
397 _write_safe(STDERR_FILENO, bufcmd, ed->slave.scmd);
402 bufcmd += *size_path;
405 size_key = (int *)bufcmd;
406 bufcmd += sizeof(*size_key);
408 if (*size_key) thumb_key = bufcmd;
410 _generated_cb(ed, *success, thumb_path, thumb_key);
412 free(ed->slave.bufcmd);
413 ed->slave.bufcmd = NULL;
418 _ethumbd_slave_alloc_cmd(struct _Ethumbd *ed, int ssize, char *sdata)
422 if (ed->slave.bufcmd)
426 if (ssize < sizeof(*scmd)) {
427 ERR("could not read size of command.");
430 ed->slave.bufcmd = malloc(*scmd);
431 ed->slave.scmd = *scmd;
434 return sizeof(*scmd);
438 _ethumbd_slave_data_read_cb(void *data, int type, void *event)
440 struct _Ethumbd *ed = data;
441 Ecore_Exe_Event_Data *ev = event;
445 if (ev->exe != ed->slave.exe)
447 ERR("PARENT ERROR: slave != ev->exe");
454 if (!_write_safe(STDERR_FILENO, sdata, ssize))
459 if (!ed->slave.bufcmd)
462 n = _ethumbd_slave_alloc_cmd(ed, ssize, sdata);
470 bdata = ed->slave.bufcmd + ed->slave.pcmd;
471 nbytes = ed->slave.scmd - ed->slave.pcmd;
472 nbytes = ssize < nbytes ? ssize : nbytes;
473 memcpy(bdata, sdata, nbytes);
476 ed->slave.pcmd += nbytes;
478 if (ed->slave.pcmd == ed->slave.scmd)
479 _ethumbd_slave_cmd_ready(ed);
487 _ethumbd_slave_del_cb(void *data, int type, void *event)
489 struct _Ethumbd *ed = data;
490 Ecore_Exe_Event_Del *ev = event;
493 if (ev->exe != ed->slave.exe)
497 ERR("slave exited with code: %d", ev->exit_code);
498 else if (ev->signalled)
499 ERR("slave exited by signal: %d", ev->exit_signal);
504 i = ed->queue.current;
505 ERR("failed to generate thumbnail for: \"%s:%s\"",
506 ed->processing->file, ed->processing->key);
508 if (ed->queue.table[i].used)
509 _ethumb_dbus_generated_signal
510 (ed, &ed->processing->id, NULL, NULL, EINA_FALSE);
511 eina_stringshare_del(ed->processing->file);
512 eina_stringshare_del(ed->processing->key);
513 eina_stringshare_del(ed->processing->thumb);
514 eina_stringshare_del(ed->processing->thumb_key);
515 free(ed->processing);
516 ed->processing = NULL;
519 ed->slave.exe = NULL;
520 if (ed->slave.bufcmd)
521 free(ed->slave.bufcmd);
523 return _ethumbd_slave_spawn(ed);
527 _ethumbd_pipe_write_setup(struct _Ethumbd *ed, int type, const void *data)
530 const float *f_value;
532 _ethumbd_write_safe(ed, &type, sizeof(type));
539 case ETHUMBD_QUALITY:
540 case ETHUMBD_COMPRESS:
543 case ETHUMBD_DOCUMENT_PAGE:
544 case ETHUMBD_VIDEO_NTIMES:
545 case ETHUMBD_VIDEO_FPS:
547 _ethumbd_write_safe(ed, i_value, sizeof(*i_value));
551 case ETHUMBD_VIDEO_TIME:
552 case ETHUMBD_VIDEO_START:
553 case ETHUMBD_VIDEO_INTERVAL:
555 _ethumbd_write_safe(ed, f_value, sizeof(*f_value));
557 case ETHUMBD_DIRECTORY:
558 case ETHUMBD_CATEGORY:
559 case ETHUMBD_FRAME_FILE:
560 case ETHUMBD_FRAME_GROUP:
561 case ETHUMBD_FRAME_SWALLOW:
562 _ethumbd_pipe_str_write(ed, data);
564 case ETHUMBD_SETUP_FINISHED:
567 ERR("wrong ethumb setup parameter.");
572 _process_setup(struct _Ethumbd *ed)
574 int op_id = ETHUMBD_OP_SETUP;
575 int index = ed->queue.current;
577 struct _Ethumb_Setup *setup = &ed->processing->setup;
579 _ethumbd_write_safe(ed, &op_id, sizeof(op_id));
580 _ethumbd_write_safe(ed, &index, sizeof(index));
582 if (setup->flags.fdo)
583 _ethumbd_pipe_write_setup(ed, ETHUMBD_FDO, &setup->fdo);
584 if (setup->flags.size)
586 _ethumbd_pipe_write_setup(ed, ETHUMBD_SIZE_W, &setup->tw);
587 _ethumbd_pipe_write_setup(ed, ETHUMBD_SIZE_H, &setup->th);
589 if (setup->flags.format)
590 _ethumbd_pipe_write_setup(ed, ETHUMBD_FORMAT, &setup->format);
591 if (setup->flags.aspect)
592 _ethumbd_pipe_write_setup(ed, ETHUMBD_ASPECT, &setup->aspect);
593 if (setup->flags.crop)
595 _ethumbd_pipe_write_setup(ed, ETHUMBD_CROP_X, &setup->cx);
596 _ethumbd_pipe_write_setup(ed, ETHUMBD_CROP_Y, &setup->cy);
598 if (setup->flags.quality)
599 _ethumbd_pipe_write_setup(ed, ETHUMBD_QUALITY, &setup->quality);
600 if (setup->flags.compress)
601 _ethumbd_pipe_write_setup(ed, ETHUMBD_COMPRESS, &setup->compress);
602 if (setup->flags.directory)
603 _ethumbd_pipe_write_setup(ed, ETHUMBD_DIRECTORY, setup->directory);
604 if (setup->flags.category)
605 _ethumbd_pipe_write_setup(ed, ETHUMBD_CATEGORY, setup->category);
606 if (setup->flags.frame)
608 _ethumbd_pipe_write_setup(ed, ETHUMBD_FRAME_FILE, setup->theme_file);
609 _ethumbd_pipe_write_setup(ed, ETHUMBD_FRAME_GROUP, setup->group);
610 _ethumbd_pipe_write_setup(ed, ETHUMBD_FRAME_SWALLOW, setup->swallow);
612 if (setup->flags.video_time)
613 _ethumbd_pipe_write_setup(ed, ETHUMBD_VIDEO_TIME, &setup->video_time);
614 if (setup->flags.video_start)
615 _ethumbd_pipe_write_setup(ed, ETHUMBD_VIDEO_START, &setup->video_start);
616 if (setup->flags.video_interval)
617 _ethumbd_pipe_write_setup(ed, ETHUMBD_VIDEO_INTERVAL,
618 &setup->video_interval);
619 if (setup->flags.video_ntimes)
620 _ethumbd_pipe_write_setup(ed, ETHUMBD_VIDEO_NTIMES, &setup->video_ntimes);
621 if (setup->flags.video_fps)
622 _ethumbd_pipe_write_setup(ed, ETHUMBD_VIDEO_FPS, &setup->video_fps);
623 if (setup->flags.document_page)
624 _ethumbd_pipe_write_setup(ed, ETHUMBD_DOCUMENT_PAGE,
625 &setup->document_page);
626 _ethumbd_pipe_write_setup(ed, ETHUMBD_SETUP_FINISHED, NULL);
629 if (setup->directory) eina_stringshare_del(setup->directory);
630 if (setup->category) eina_stringshare_del(setup->category);
631 if (setup->theme_file) eina_stringshare_del(setup->theme_file);
632 if (setup->group) eina_stringshare_del(setup->group);
633 if (setup->swallow) eina_stringshare_del(setup->swallow);
635 free(ed->processing);
636 ed->processing = NULL;
640 _process_file(struct _Ethumbd *ed)
642 _ethumbd_child_write_op_generate
643 (ed, ed->queue.current, ed->processing->file,
644 ed->processing->key, ed->processing->thumb, ed->processing->thumb_key);
648 _get_next_on_queue(struct _Ethumb_Queue *queue)
651 struct _Ethumb_Object *eobject;
655 if (i >= queue->count)
658 index = queue->list[i];
659 eobject = &(queue->table[index]);
660 while (!eobject->nqueue)
662 i = (i + 1) % queue->count;
664 index = queue->list[i];
665 eobject = &(queue->table[index]);
668 return queue->list[i];
672 _process_queue_cb(void *data)
674 struct _Ethumb_Object *eobject;
676 struct _Ethumbd *ed = data;
677 struct _Ethumb_Queue *queue = &ed->queue;
678 struct _Ethumb_Request *request;
687 _ethumbd_timeout_start(ed);
692 i = _get_next_on_queue(queue);
693 eobject = &(queue->table[i]);
695 request = eina_list_data_get(eobject->queue);
696 eobject->queue = eina_list_remove_list(eobject->queue, eobject->queue);
697 ed->queue.current = i;
698 DBG("processing file: \"%s:%s\"...", request->file,
700 ed->processing = request;
707 _ethumb_dbus_inc_min_id(eobject);
718 _process_queue_start(struct _Ethumbd *ed)
721 ed->idler = ecore_idler_add(_process_queue_cb, ed);
725 _process_queue_stop(struct _Ethumbd *ed)
729 ecore_idler_del(ed->idler);
735 _ethumb_table_append(struct _Ethumbd *ed)
739 struct _Ethumb_Queue *q = &ed->queue;
741 if (q->count == q->max_count)
743 int new_max = q->max_count + 5;
747 start = q->max_count;
748 size = new_max - q->max_count;
750 tmp = realloc(q->table, new_max * sizeof(struct _Ethumb_Object));
753 CRIT("could not realloc q->table to %zd bytes: %s",
754 new_max * sizeof(struct _Ethumb_Object), strerror(errno));
758 memset(&q->table[start], 0, size * sizeof(struct _Ethumb_Object));
760 tmp = realloc(q->list, new_max * sizeof(int));
763 CRIT("could not realloc q->list to %zd bytes: %s",
764 new_max * sizeof(int), strerror(errno));
769 q->max_count = new_max;
772 for (i = 0; i < q->max_count; i++)
774 if (!q->table[i].used)
778 snprintf(buf, sizeof(buf), "%s/%d", _ethumb_dbus_path, i);
779 q->table[i].used = 1;
780 q->table[i].path = eina_stringshare_add(buf);
781 q->table[i].max_id = -1;
782 q->table[i].min_id = -1;
783 q->list[q->count] = i;
785 DBG("new object: %s, index = %d, count = %d", buf, i, q->count);
791 _get_index_for_path(const char *path)
795 n = sscanf(path, "/org/enlightenment/Ethumb/%d", &i);
802 _ethumb_table_del(struct _Ethumbd *ed, int i)
807 struct _Ethumb_Queue *q = &ed->queue;
808 struct _Ethumb_Object_Data *odata;
810 eina_stringshare_del(q->table[i].path);
812 l = q->table[i].queue;
815 struct _Ethumb_Request *request = l->data;
816 eina_stringshare_del(request->file);
817 eina_stringshare_del(request->key);
818 eina_stringshare_del(request->thumb);
819 eina_stringshare_del(request->thumb_key);
821 l = eina_list_remove_list(l, l);
823 q->nqueue -= q->table[i].nqueue;
825 il = e_dbus_object_interfaces_get(q->table[i].dbus_obj);
828 e_dbus_object_interface_detach(q->table[i].dbus_obj, il->data);
829 il = e_dbus_object_interfaces_get(q->table[i].dbus_obj);
831 odata = e_dbus_object_data_get(q->table[i].dbus_obj);
833 e_dbus_object_free(q->table[i].dbus_obj);
835 memset(&(q->table[i]), 0, sizeof(struct _Ethumb_Object));
836 for (j = 0; j < q->count; j++)
839 q->list[j] = q->list[q->count - 1];
843 _ethumbd_child_write_op_del(ed, i);
844 if (!q->count && !ed->processing)
845 _ethumbd_timeout_start(ed);
849 _ethumb_table_clear(struct _Ethumbd *ed)
853 for (i = 0; i < ed->queue.max_count; i++)
854 if (ed->queue.table[i].used)
855 _ethumb_table_del(ed, i);
859 _name_owner_changed_cb(void *data, DBusMessage *msg)
862 struct _Ethumbd *ed = data;
863 struct _Ethumb_Queue *q = &ed->queue;
864 const char *name, *from, *to;
867 dbus_error_init(&err);
868 if (!dbus_message_get_args(msg, &err,
869 DBUS_TYPE_STRING, &name,
870 DBUS_TYPE_STRING, &from,
871 DBUS_TYPE_STRING, &to,
874 ERR("could not get NameOwnerChanged arguments: %s: %s",
875 err.name, err.message);
876 dbus_error_free(&err);
880 DBG("NameOwnerChanged: name = %s, from = %s, to = %s", name, from, to);
882 if (from[0] == '\0' || to[0] != '\0')
885 from = eina_stringshare_add(from);
886 for (i = 0; i < q->max_count; i++)
888 if (q->table[i].used && q->table[i].client == from)
890 _ethumb_table_del(ed, i);
891 DBG("deleting [%d] from queue table.", i);
897 _ethumb_dbus_add_name_owner_changed_cb(struct _Ethumbd *ed)
899 ed->name_owner_changed_handler = e_dbus_signal_handler_add
900 (ed->conn, fdo_bus_name, fdo_path, fdo_interface, "NameOwnerChanged",
901 _name_owner_changed_cb, ed);
905 _ethumb_dbus_ethumb_new_cb(E_DBus_Object *object, DBusMessage *msg)
908 DBusMessageIter iter;
909 E_DBus_Object *dbus_object;
910 struct _Ethumb_Object_Data *odata;
912 const char *return_path = "";
916 ed = e_dbus_object_data_get(object);
917 client = dbus_message_get_sender(msg);
921 i = _ethumb_table_append(ed);
925 odata = calloc(1, sizeof(*odata));
929 ed->queue.table[i].client = eina_stringshare_add(client);
930 return_path = ed->queue.table[i].path;
932 dbus_object = e_dbus_object_add(ed->conn, return_path, odata);
935 ERR("could not create dbus_object.");
941 e_dbus_object_interface_attach(dbus_object, ed->objects_iface);
942 ed->queue.table[i].dbus_obj = dbus_object;
944 _ethumbd_child_write_op_new(ed, i);
945 _ethumbd_timeout_stop(ed);
948 reply = dbus_message_new_method_return(msg);
949 dbus_message_iter_init_append(reply, &iter);
950 dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
955 static struct _Ethumb_DBus_Method_Table _ethumb_dbus_methods[] =
957 {"new", "", "o", _ethumb_dbus_ethumb_new_cb},
958 {NULL, NULL, NULL, NULL}
962 _ethumb_dbus_get_bytearray(DBusMessageIter *iter)
966 DBusMessageIter riter;
969 el_type = dbus_message_iter_get_element_type(iter);
970 if (el_type != DBUS_TYPE_BYTE)
972 ERR("not an byte array element.");
976 dbus_message_iter_recurse(iter, &riter);
977 dbus_message_iter_get_fixed_array(&riter, &result, &length);
979 if ((length == 0) || (result[0] == '\0'))
982 return eina_stringshare_add_length(result, length);
986 _ethumb_dbus_append_bytearray(DBusMessageIter *iter, const char *string)
988 DBusMessageIter viter;
993 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &viter);
994 dbus_message_iter_append_fixed_array
995 (&viter, DBUS_TYPE_BYTE, &string, strlen(string) + 1);
996 dbus_message_iter_close_container(iter, &viter);
1000 _ethumb_dbus_queue_add_cb(E_DBus_Object *object, DBusMessage *msg)
1003 DBusMessageIter iter;
1004 const char *file, *key;
1005 const char *thumb, *thumb_key;
1006 struct _Ethumb_Object_Data *odata;
1007 struct _Ethumb_Object *eobject;
1008 struct _Ethumbd *ed;
1009 struct _Ethumb_Request *request;
1010 dbus_int32_t id = -1;
1012 dbus_message_iter_init(msg, &iter);
1013 dbus_message_iter_get_basic(&iter, &id);
1014 dbus_message_iter_next(&iter);
1015 file = _ethumb_dbus_get_bytearray(&iter);
1016 dbus_message_iter_next(&iter);
1017 key = _ethumb_dbus_get_bytearray(&iter);
1018 dbus_message_iter_next(&iter);
1019 thumb = _ethumb_dbus_get_bytearray(&iter);
1020 dbus_message_iter_next(&iter);
1021 thumb_key = _ethumb_dbus_get_bytearray(&iter);
1025 ERR("no filename given.");
1029 odata = e_dbus_object_data_get(object);
1032 ERR("could not get dbus_object data.");
1037 eobject = &(ed->queue.table[odata->index]);
1038 if (!_ethumb_dbus_check_id(eobject, id))
1040 request = calloc(1, sizeof(*request));
1042 request->file = file;
1044 request->thumb = thumb;
1045 request->thumb_key = thumb_key;
1046 eobject->queue = eina_list_append(eobject->queue, request);
1049 _ethumb_dbus_inc_max_id(eobject, id);
1051 _process_queue_start(ed);
1054 reply = dbus_message_new_method_return(msg);
1055 dbus_message_iter_init_append(reply, &iter);
1056 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &id);
1061 _ethumb_dbus_queue_remove_cb(E_DBus_Object *object, DBusMessage *msg)
1064 DBusMessageIter iter;
1066 struct _Ethumb_Object_Data *odata;
1067 struct _Ethumb_Object *eobject;
1068 struct _Ethumb_Request *request;
1069 struct _Ethumbd *ed;
1073 dbus_message_iter_init(msg, &iter);
1074 dbus_message_iter_get_basic(&iter, &id);
1076 odata = e_dbus_object_data_get(object);
1079 ERR("could not get dbus_object data.");
1084 eobject = &ed->queue.table[odata->index];
1089 if (id == request->id)
1097 eina_stringshare_del(request->file);
1098 eina_stringshare_del(request->key);
1099 eina_stringshare_del(request->thumb);
1100 eina_stringshare_del(request->thumb_key);
1102 eobject->queue = eina_list_remove_list(eobject->queue, l);
1105 _ethumb_dbus_inc_min_id(eobject);
1109 reply = dbus_message_new_method_return(msg);
1110 dbus_message_iter_init_append(reply, &iter);
1111 dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &r);
1116 _ethumb_dbus_queue_clear_cb(E_DBus_Object *object, DBusMessage *msg)
1119 struct _Ethumb_Object_Data *odata;
1120 struct _Ethumb_Object *eobject;
1121 struct _Ethumbd *ed;
1124 odata = e_dbus_object_data_get(object);
1127 ERR("could not get dbus_object data.");
1132 eobject = &ed->queue.table[odata->index];
1136 struct _Ethumb_Request *request = l->data;
1137 eina_stringshare_del(request->file);
1138 eina_stringshare_del(request->key);
1139 eina_stringshare_del(request->thumb);
1140 eina_stringshare_del(request->thumb_key);
1142 l = eina_list_remove_list(l, l);
1144 ed->queue.nqueue -= eobject->nqueue;
1145 eobject->nqueue = 0;
1148 reply = dbus_message_new_method_return(msg);
1153 _ethumb_dbus_delete_cb(E_DBus_Object *object, DBusMessage *msg)
1156 DBusMessageIter iter;
1157 struct _Ethumb_Object_Data *odata;
1158 struct _Ethumbd *ed;
1160 dbus_message_iter_init(msg, &iter);
1161 reply = dbus_message_new_method_return(msg);
1163 odata = e_dbus_object_data_get(object);
1166 ERR("could not get dbus_object data for del_cb.");
1170 _ethumb_table_del(ed, odata->index);
1177 _ethumb_dbus_fdo_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request __UNUSED__)
1182 type = dbus_message_iter_get_arg_type(iter);
1183 if (type != DBUS_TYPE_INT32)
1185 ERR("invalid param for fdo_set.");
1189 dbus_message_iter_get_basic(iter, &fdo);
1190 DBG("setting fdo to: %d", fdo);
1196 _ethumb_dbus_size_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1198 DBusMessageIter oiter;
1202 type = dbus_message_iter_get_arg_type(iter);
1203 if (type != DBUS_TYPE_STRUCT)
1205 ERR("invalid param for size_set.");
1209 dbus_message_iter_recurse(iter, &oiter);
1210 dbus_message_iter_get_basic(&oiter, &w);
1211 dbus_message_iter_next(&oiter);
1212 dbus_message_iter_get_basic(&oiter, &h);
1213 DBG("setting size to: %dx%d", w, h);
1214 request->setup.flags.size = 1;
1215 request->setup.tw = w;
1216 request->setup.th = h;
1222 _ethumb_dbus_format_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1225 dbus_int32_t format;
1227 type = dbus_message_iter_get_arg_type(iter);
1228 if (type != DBUS_TYPE_INT32)
1230 ERR("invalid param for format_set.");
1234 dbus_message_iter_get_basic(iter, &format);
1235 DBG("setting format to: %d", format);
1236 request->setup.flags.format = 1;
1237 request->setup.format = format;
1243 _ethumb_dbus_aspect_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1246 dbus_int32_t aspect;
1248 type = dbus_message_iter_get_arg_type(iter);
1249 if (type != DBUS_TYPE_INT32)
1251 ERR("invalid param for aspect_set.");
1255 dbus_message_iter_get_basic(iter, &aspect);
1256 DBG("setting aspect to: %d", aspect);
1257 request->setup.flags.aspect = 1;
1258 request->setup.aspect = aspect;
1264 _ethumb_dbus_crop_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1266 DBusMessageIter oiter;
1270 type = dbus_message_iter_get_arg_type(iter);
1271 if (type != DBUS_TYPE_STRUCT)
1273 ERR("invalid param for crop_set.");
1277 dbus_message_iter_recurse(iter, &oiter);
1278 dbus_message_iter_get_basic(&oiter, &x);
1279 dbus_message_iter_next(&oiter);
1280 dbus_message_iter_get_basic(&oiter, &y);
1281 DBG("setting crop to: %3.2f,%3.2f", x, y);
1282 request->setup.flags.crop = 1;
1283 request->setup.cx = x;
1284 request->setup.cy = y;
1290 _ethumb_dbus_quality_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1293 dbus_int32_t quality;
1295 type = dbus_message_iter_get_arg_type(iter);
1296 if (type != DBUS_TYPE_INT32)
1298 ERR("invalid param for quality_set.");
1302 dbus_message_iter_get_basic(iter, &quality);
1303 DBG("setting quality to: %d", quality);
1304 request->setup.flags.quality = 1;
1305 request->setup.quality = quality;
1312 _ethumb_dbus_compress_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1315 dbus_int32_t compress;
1317 type = dbus_message_iter_get_arg_type(iter);
1318 if (type != DBUS_TYPE_INT32)
1320 ERR("invalid param for compress_set.");
1324 dbus_message_iter_get_basic(iter, &compress);
1325 DBG("setting compress to: %d", compress);
1326 request->setup.flags.compress = 1;
1327 request->setup.compress = compress;
1333 _ethumb_dbus_frame_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1335 DBusMessageIter oiter;
1337 const char *file, *group, *swallow;
1339 type = dbus_message_iter_get_arg_type(iter);
1340 if (type != DBUS_TYPE_STRUCT)
1342 ERR("invalid param for frame_set.");
1346 dbus_message_iter_recurse(iter, &oiter);
1347 file = _ethumb_dbus_get_bytearray(&oiter);
1348 dbus_message_iter_next(&oiter);
1349 group = _ethumb_dbus_get_bytearray(&oiter);
1350 dbus_message_iter_next(&oiter);
1351 swallow = _ethumb_dbus_get_bytearray(&oiter);
1352 DBG("setting frame to \"%s:%s:%s\"", file, group, swallow);
1353 request->setup.flags.frame = 1;
1354 request->setup.theme_file = eina_stringshare_add(file);
1355 request->setup.group = eina_stringshare_add(group);
1356 request->setup.swallow = eina_stringshare_add(swallow);
1362 _ethumb_dbus_directory_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1365 const char *directory;
1367 type = dbus_message_iter_get_arg_type(iter);
1368 if (type != DBUS_TYPE_ARRAY)
1370 ERR("invalid param for dir_path_set.");
1374 directory = _ethumb_dbus_get_bytearray(iter);
1375 DBG("setting directory to: %s", directory);
1376 request->setup.flags.directory = 1;
1377 request->setup.directory = eina_stringshare_add(directory);
1383 _ethumb_dbus_category_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1386 const char *category;
1388 type = dbus_message_iter_get_arg_type(iter);
1389 if (type != DBUS_TYPE_ARRAY)
1391 ERR("invalid param for category.");
1395 category = _ethumb_dbus_get_bytearray(iter);
1396 DBG("setting category to: %s", category);
1397 request->setup.flags.category = 1;
1398 request->setup.category = eina_stringshare_add(category);
1404 _ethumb_dbus_video_time_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1409 type = dbus_message_iter_get_arg_type(iter);
1410 if (type != DBUS_TYPE_DOUBLE)
1412 ERR("invalid param for video_time_set.");
1416 dbus_message_iter_get_basic(iter, &video_time);
1417 DBG("setting video_time to: %3.2f", video_time);
1418 request->setup.flags.video_time = 1;
1419 request->setup.video_time = video_time;
1425 _ethumb_dbus_video_start_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1430 type = dbus_message_iter_get_arg_type(iter);
1431 if (type != DBUS_TYPE_DOUBLE)
1433 ERR("invalid param for video_start_set.");
1437 dbus_message_iter_get_basic(iter, &video_start);
1438 DBG("setting video_start to: %3.2f", video_start);
1439 request->setup.flags.video_start = 1;
1440 request->setup.video_start = video_start;
1446 _ethumb_dbus_video_interval_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1449 double video_interval;
1451 type = dbus_message_iter_get_arg_type(iter);
1452 if (type != DBUS_TYPE_DOUBLE)
1454 ERR("invalid param for video_interval_set.");
1458 dbus_message_iter_get_basic(iter, &video_interval);
1459 DBG("setting video_interval to: %3.2f", video_interval);
1460 request->setup.flags.video_interval = 1;
1461 request->setup.video_interval = video_interval;
1467 _ethumb_dbus_video_ntimes_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1470 unsigned int video_ntimes;
1472 type = dbus_message_iter_get_arg_type(iter);
1473 if (type != DBUS_TYPE_UINT32)
1475 ERR("invalid param for video_ntimes_set.");
1479 dbus_message_iter_get_basic(iter, &video_ntimes);
1480 DBG("setting video_ntimes to: %3.2d", video_ntimes);
1481 request->setup.flags.video_ntimes = 1;
1482 request->setup.video_ntimes = video_ntimes;
1488 _ethumb_dbus_video_fps_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1491 unsigned int video_fps;
1493 type = dbus_message_iter_get_arg_type(iter);
1494 if (type != DBUS_TYPE_UINT32)
1496 ERR("invalid param for video_fps_set.");
1500 dbus_message_iter_get_basic(iter, &video_fps);
1501 DBG("setting video_fps to: %3.2d", video_fps);
1502 request->setup.flags.video_fps = 1;
1503 request->setup.video_fps = video_fps;
1509 _ethumb_dbus_document_page_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
1512 unsigned int document_page;
1514 type = dbus_message_iter_get_arg_type(iter);
1515 if (type != DBUS_TYPE_UINT32)
1517 ERR("invalid param for document_page_set.");
1521 dbus_message_iter_get_basic(iter, &document_page);
1522 DBG("setting document_page to: %d", document_page);
1523 request->setup.flags.document_page = 1;
1524 request->setup.document_page = document_page;
1532 int (*setup_func)(struct _Ethumb_Object *eobject, DBusMessageIter *iter, struct _Ethumb_Request *request);
1534 {"fdo", _ethumb_dbus_fdo_set},
1535 {"size", _ethumb_dbus_size_set},
1536 {"format", _ethumb_dbus_format_set},
1537 {"aspect", _ethumb_dbus_aspect_set},
1538 {"crop", _ethumb_dbus_crop_set},
1539 {"quality", _ethumb_dbus_quality_set},
1540 {"compress", _ethumb_dbus_compress_set},
1541 {"frame", _ethumb_dbus_frame_set},
1542 {"directory", _ethumb_dbus_directory_set},
1543 {"category", _ethumb_dbus_category_set},
1544 {"video_time", _ethumb_dbus_video_time_set},
1545 {"video_start", _ethumb_dbus_video_start_set},
1546 {"video_interval", _ethumb_dbus_video_interval_set},
1547 {"video_ntimes", _ethumb_dbus_video_ntimes_set},
1548 {"video_fps", _ethumb_dbus_video_fps_set},
1549 {"document_page", _ethumb_dbus_document_page_set},
1554 _ethumb_dbus_ethumb_setup_parse_element(struct _Ethumb_Object *eobject, DBusMessageIter *iter, struct _Ethumb_Request *request)
1556 DBusMessageIter viter, diter;
1560 dbus_message_iter_recurse(iter, &diter);
1561 dbus_message_iter_get_basic(&diter, &option);
1562 dbus_message_iter_next(&diter);
1565 for (i = 0; _option_cbs[i].option; i++)
1566 if (!strcmp(_option_cbs[i].option, option))
1574 ERR("ethumb_setup invalid option: %s", option);
1578 dbus_message_iter_recurse(&diter, &viter);
1579 return _option_cbs[i].setup_func(eobject, &viter, request);
1583 _ethumb_dbus_ethumb_setup_cb(E_DBus_Object *object, DBusMessage *msg)
1586 DBusMessageIter iter, aiter;
1587 struct _Ethumb_Object_Data *odata;
1588 struct _Ethumbd *ed;
1589 struct _Ethumb_Object *eobject;
1590 struct _Ethumb_Request *request;
1594 dbus_message_iter_init(msg, &iter);
1595 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1597 ERR("wrong parameters.");
1601 odata = e_dbus_object_data_get(object);
1604 ERR("could not get dbus_object data for setup_cb.");
1609 eobject = &ed->queue.table[odata->index];
1611 request = calloc(1, sizeof(*request));
1613 dbus_message_iter_recurse(&iter, &aiter);
1614 atype = dbus_message_iter_get_arg_type(&aiter);
1617 while (atype != DBUS_TYPE_INVALID)
1619 if (!_ethumb_dbus_ethumb_setup_parse_element(eobject, &aiter, request))
1621 dbus_message_iter_next(&aiter);
1622 atype = dbus_message_iter_get_arg_type(&aiter);
1625 eobject->queue = eina_list_append(eobject->queue, request);
1630 reply = dbus_message_new_method_return(msg);
1631 dbus_message_iter_init_append(reply, &iter);
1632 dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &r);
1638 _ethumb_dbus_generated_signal(struct _Ethumbd *ed, int *id, const char *thumb_path, const char *thumb_key, Eina_Bool success)
1640 DBusMessage *signal;
1643 DBusMessageIter iter;
1650 current = ed->queue.current;
1651 opath = ed->queue.table[current].path;
1652 signal = dbus_message_new_signal
1653 (opath, _ethumb_dbus_objects_interface, "generated");
1655 dbus_message_iter_init_append(signal, &iter);
1656 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &id32);
1657 _ethumb_dbus_append_bytearray(&iter, thumb_path);
1658 _ethumb_dbus_append_bytearray(&iter, thumb_key);
1659 dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &value);
1661 e_dbus_message_send(ed->conn, signal, NULL, -1, NULL);
1662 dbus_message_unref(signal);
1665 static struct _Ethumb_DBus_Method_Table _ethumb_dbus_objects_methods[] = {
1666 {"queue_add", "iayayayay", "i", _ethumb_dbus_queue_add_cb},
1667 {"queue_remove", "i", "b", _ethumb_dbus_queue_remove_cb},
1668 {"clear_queue", "", "", _ethumb_dbus_queue_clear_cb},
1669 {"ethumb_setup", "a{sv}", "b", _ethumb_dbus_ethumb_setup_cb},
1670 {"delete", "", "", _ethumb_dbus_delete_cb},
1671 {NULL, NULL, NULL, NULL}
1674 static struct _Ethumb_DBus_Signal_Table _ethumb_dbus_objects_signals[] = {
1675 {"generated", "iayayb"},
1680 _ethumb_dbus_interface_elements_add(E_DBus_Interface *iface, struct _Ethumb_DBus_Method_Table *mtable, struct _Ethumb_DBus_Signal_Table *stable)
1683 while (mtable && mtable[++i].name != NULL)
1684 if (!e_dbus_interface_method_add(iface,
1686 mtable[i].signature,
1688 mtable[i].function))
1692 while (stable && stable[++i].name != NULL)
1693 if (!e_dbus_interface_signal_add(iface,
1695 stable[i].signature))
1701 _ethumb_dbus_request_name_cb(void *data, DBusMessage *msg __UNUSED__, DBusError *err)
1703 E_DBus_Object *dbus_object;
1704 struct _Ethumbd *ed = data;
1707 if (dbus_error_is_set(err))
1709 ERR("request name error: %s", err->message);
1710 dbus_error_free(err);
1711 e_dbus_connection_close(ed->conn);
1715 dbus_object = e_dbus_object_add(ed->conn, _ethumb_dbus_path, ed);
1718 ed->dbus_obj = dbus_object;
1719 ed->eiface = e_dbus_interface_new(_ethumb_dbus_interface);
1722 ERR("could not create interface.");
1725 r = _ethumb_dbus_interface_elements_add(ed->eiface,
1726 _ethumb_dbus_methods, NULL);
1729 ERR("could not add methods to the interface.");
1730 e_dbus_interface_unref(ed->eiface);
1733 e_dbus_object_interface_attach(dbus_object, ed->eiface);
1735 ed->objects_iface = e_dbus_interface_new(_ethumb_dbus_objects_interface);
1736 if (!ed->objects_iface)
1738 ERR("could not create interface.");
1742 r = _ethumb_dbus_interface_elements_add(ed->objects_iface,
1743 _ethumb_dbus_objects_methods,
1744 _ethumb_dbus_objects_signals);
1747 ERR("ERROR: could not setup objects interface methods.");
1748 e_dbus_interface_unref(ed->objects_iface);
1752 _ethumb_dbus_add_name_owner_changed_cb(ed);
1754 _ethumbd_timeout_start(ed);
1758 _ethumb_dbus_setup(struct _Ethumbd *ed)
1761 (ed->conn, _ethumb_dbus_bus_name, 0, _ethumb_dbus_request_name_cb, ed);
1767 _ethumb_dbus_finish(struct _Ethumbd *ed)
1769 _process_queue_stop(ed);
1770 _ethumb_table_clear(ed);
1771 e_dbus_signal_handler_del(ed->conn, ed->name_owner_changed_handler);
1772 e_dbus_interface_unref(ed->objects_iface);
1773 e_dbus_interface_unref(ed->eiface);
1774 e_dbus_object_free(ed->dbus_obj);
1775 free(ed->queue.table);
1776 free(ed->queue.list);
1780 _ethumbd_slave_spawn(struct _Ethumbd *ed)
1782 ed->slave.data_cb = ecore_event_handler_add(
1783 ECORE_EXE_EVENT_DATA, _ethumbd_slave_data_read_cb, ed);
1784 ed->slave.del_cb = ecore_event_handler_add(
1785 ECORE_EXE_EVENT_DEL, _ethumbd_slave_del_cb, ed);
1787 ed->slave.bufcmd = NULL;
1790 ed->slave.exe = ecore_exe_pipe_run(
1791 ETHUMB_LIBEXEC_DIR"/ethumbd_slave",
1792 ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE, ed);
1795 ERR("could not create slave.");
1803 main(int argc, char *argv[])
1805 Eina_Bool quit_option = 0;
1810 double timeout = -1;
1812 memset(&ed, 0, sizeof(ed));
1818 if (_log_domain < 0)
1820 _log_domain = eina_log_domain_register("ethumbd", NULL);
1821 if (_log_domain < 0)
1823 EINA_LOG_CRIT("could not register log domain 'ethumbd'");
1829 child = _ethumbd_slave_spawn(&ed);
1844 ERR("could not init e_dbus.");
1849 Ecore_Getopt_Value values[] = {
1850 ECORE_GETOPT_VALUE_DOUBLE(timeout),
1851 ECORE_GETOPT_VALUE_BOOL(quit_option),
1852 ECORE_GETOPT_VALUE_BOOL(quit_option),
1853 ECORE_GETOPT_VALUE_BOOL(quit_option),
1854 ECORE_GETOPT_VALUE_BOOL(quit_option),
1855 ECORE_GETOPT_VALUE_NONE
1858 arg_index = ecore_getopt_parse(&optdesc, values, argc, argv);
1861 ERR("Could not parse arguments.");
1869 ed.conn = e_dbus_bus_get(DBUS_BUS_SESSION);
1872 ERR("could not connect to session bus.");
1877 ed.timeout = timeout;
1879 if (!_ethumb_dbus_setup(&ed))
1881 e_dbus_connection_close(ed.conn);
1882 ERR("could not setup dbus connection.");
1887 ecore_main_loop_begin();
1888 _ethumb_dbus_finish(&ed);
1891 if (_log_domain >= 0)
1893 eina_log_domain_unregister(_log_domain);
1900 ecore_exe_quit(ed.slave.exe);