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>
40 #include "ethumbd_private.h"
46 #define MAX_ID 2000000
48 #define DBG(...) EINA_LOG_DOM_DBG(_log_domain, __VA_ARGS__)
49 #define INF(...) EINA_LOG_DOM_INFO(_log_domain, __VA_ARGS__)
50 #define WRN(...) EINA_LOG_DOM_WARN(_log_domain, __VA_ARGS__)
51 #define ERR(...) EINA_LOG_DOM_ERR(_log_domain, __VA_ARGS__)
52 #define CRIT(...) EINA_LOG_DOM_CRIT(_log_domain, __VA_ARGS__)
54 static const char _ethumb_dbus_bus_name[] = "org.enlightenment.Ethumb";
55 static const char _ethumb_dbus_interface[] = "org.enlightenment.Ethumb";
56 static const char _ethumb_dbus_objects_interface[] = "org.enlightenment.Ethumb.objects";
57 static const char _ethumb_dbus_path[] = "/org/enlightenment/Ethumb";
58 static const char fdo_interface[] = "org.freedesktop.DBus";
59 static const char fdo_bus_name[] = "org.freedesktop.DBus";
60 static const char fdo_path[] = "/org/freedesktop/DBus";
62 static int _log_domain = -1;
64 typedef struct _Ethumbd_Setup Ethumbd_Setup;
65 typedef struct _Ethumbd_Slave Ethumbd_Slave;
66 typedef struct _Ethumbd_Request Ethumbd_Request;
67 typedef struct _Ethumbd_Queue Ethumbd_Queue;
68 typedef struct _Ethumbd_Object Ethumbd_Object;
69 typedef struct _Ethumbd_Object_Data Ethumbd_Object_Data;
70 typedef struct _Ethumbd Ethumbd;
80 Eina_Bool orientation: 1;
82 Eina_Bool quality : 1;
83 Eina_Bool compress : 1;
84 Eina_Bool directory : 1;
85 Eina_Bool category : 1;
87 Eina_Bool video_time : 1;
88 Eina_Bool video_start : 1;
89 Eina_Bool video_interval : 1;
90 Eina_Bool video_ntimes : 1;
91 Eina_Bool video_fps : 1;
92 Eina_Bool document_page : 1;
102 const char *directory;
103 const char *category;
104 const char *theme_file;
109 float video_interval;
110 unsigned int video_ntimes;
111 unsigned int video_fps;
112 unsigned int document_page;
115 struct _Ethumbd_Request
118 const char *file, *key;
119 const char *thumb, *thumb_key;
123 struct _Ethumbd_Object
133 E_DBus_Object *dbus_obj;
136 struct _Ethumbd_Queue
143 Ethumbd_Object *table;
147 struct _Ethumbd_Slave
150 char *bufcmd; // buffer to read commands from slave
151 int scmd; // size of command to read
152 int pcmd; // position in the command buffer
157 E_DBus_Connection *conn;
158 E_DBus_Signal_Handler *name_owner_changed_handler;
159 E_DBus_Interface *eiface, *objects_iface;
160 E_DBus_Object *dbus_obj;
162 Ethumbd_Request *processing;
165 Ecore_Timer *timeout_timer;
168 Ecore_Event_Handler *data_cb;
169 Ecore_Event_Handler *del_cb;
172 struct _Ethumbd_Object_Data
178 struct _Ethumb_DBus_Method_Table
181 const char *signature;
183 E_DBus_Method_Cb function;
186 struct _Ethumb_DBus_Signal_Table
189 const char *signature;
192 const Ecore_Getopt optdesc = {
196 "(C) 2009 - ProFUSION embedded systems",
197 "LGPL v3 - GNU Lesser General Public License",
200 "ethumbd uses the Ethumb library to create thumbnails for any "
201 "program that requests it (now just by dbus).\n",
204 ECORE_GETOPT_STORE_DOUBLE
205 ('t', "timeout", "finish ethumbd after <timeout> seconds of no activity."),
206 ECORE_GETOPT_LICENSE('L', "license"),
207 ECORE_GETOPT_COPYRIGHT('C', "copyright"),
208 ECORE_GETOPT_VERSION('V', "version"),
209 ECORE_GETOPT_HELP('h', "help"),
210 ECORE_GETOPT_SENTINEL
214 static void _ethumb_dbus_generated_signal(Ethumbd *ed, int *id, const char *thumb_path, const char *thumb_key, Eina_Bool success);
215 static Eina_Bool _ethumbd_slave_spawn(Ethumbd_Slave *slave, Ethumbd *ed);
218 _ethumbd_timeout_cb(void *data)
222 ecore_main_loop_quit();
223 ed->timeout_timer = NULL;
229 _ethumbd_timeout_start(Ethumbd *ed)
234 if (!ed->timeout_timer)
235 ed->timeout_timer = ecore_timer_add(ed->timeout, _ethumbd_timeout_cb, ed);
239 _ethumbd_timeout_stop(Ethumbd *ed)
241 if (!ed->timeout_timer)
244 ecore_timer_del(ed->timeout_timer);
245 ed->timeout_timer = NULL;
249 _ethumb_dbus_check_id(Ethumbd_Object *eobject, int id)
251 if (id < 0 || id > MAX_ID)
254 if (eobject->min_id < eobject->max_id)
255 return id < eobject->min_id || id > eobject->max_id;
256 else if (eobject->min_id > eobject->max_id)
257 return id < eobject->min_id && id > eobject->max_id;
259 return id != eobject->max_id;
263 _ethumb_dbus_inc_max_id(Ethumbd_Object *eobject, int id)
265 if (eobject->min_id < 0 && eobject->max_id < 0)
266 eobject->min_id = id;
268 eobject->max_id = id;
272 _ethumb_dbus_inc_min_id(Ethumbd_Object *eobject)
279 Ethumbd_Request *request = l->data;
280 if (request->id >= 0)
282 eobject->min_id = request->id;
291 eobject->min_id = -1;
292 eobject->max_id = -1;
297 _ethumbd_write_safe(Ethumbd_Slave *slave, const void *buf, ssize_t size)
302 ERR("slave process isn't running.");
306 ecore_exe_send(slave->exe, buf, size);
311 _ethumbd_child_write_op_new(Ethumbd_Slave *slave, int idx)
313 int id = ETHUMBD_OP_NEW;
314 _ethumbd_write_safe(slave, &id, sizeof(id));
315 _ethumbd_write_safe(slave, &idx, sizeof(idx));
319 _ethumbd_child_write_op_del(Ethumbd_Slave *slave, int idx)
321 int id = ETHUMBD_OP_DEL;
322 _ethumbd_write_safe(slave, &id, sizeof(id));
323 _ethumbd_write_safe(slave, &idx, sizeof(idx));
327 _ethumbd_pipe_str_write(Ethumbd_Slave *slave, const char *str)
332 len = strlen(str) + 1;
336 _ethumbd_write_safe(slave, &len, sizeof(len));
337 _ethumbd_write_safe(slave, str, len);
341 _ethumbd_child_write_op_generate(Ethumbd_Slave *slave,
342 int idx, const char *path, const char *key,
343 const char *thumb_path, const char *thumb_key)
345 int id = ETHUMBD_OP_GENERATE;
347 _ethumbd_write_safe(slave, &id, sizeof(id));
348 _ethumbd_write_safe(slave, &idx, sizeof(idx));
350 _ethumbd_pipe_str_write(slave, path);
351 _ethumbd_pipe_str_write(slave, key);
352 _ethumbd_pipe_str_write(slave, thumb_path);
353 _ethumbd_pipe_str_write(slave, thumb_key);
357 _generated_cb(Ethumbd *ed, Eina_Bool success, const char *thumb_path, const char *thumb_key)
359 int i = ed->queue.current;
361 DBG("thumbnail ready at: \"%s:%s\"", thumb_path, thumb_key);
363 if (ed->queue.table[i].used)
364 _ethumb_dbus_generated_signal
365 (ed, &ed->processing->id, thumb_path, thumb_key, success);
366 eina_stringshare_del(ed->processing->file);
367 eina_stringshare_del(ed->processing->key);
368 eina_stringshare_del(ed->processing->thumb);
369 eina_stringshare_del(ed->processing->thumb_key);
370 free(ed->processing);
371 ed->processing = NULL;
375 _ethumbd_slave_cmd_ready(Ethumbd *ed)
377 const char *bufcmd = ed->slave.bufcmd;
379 const char *thumb_path = NULL;
380 const char *thumb_key = NULL;
381 int size_path, size_key;
383 /* NOTE: accessing values directly on bufcmd breaks alignment
384 * as the first item is an Eina_Bool (size 1) and second is
385 * an integer (size 4, alignment 4).
386 * Thus copy to stack values before using them, to have proper alignment.
388 #define READVAL(dst) \
389 memcpy(&dst, bufcmd, sizeof(dst)); \
390 bufcmd += sizeof(dst);
402 if (size_key) thumb_key = bufcmd;
406 _generated_cb(ed, success, thumb_path, thumb_key);
408 free(ed->slave.bufcmd);
409 ed->slave.bufcmd = NULL;
414 _ethumbd_slave_alloc_cmd(Ethumbd *ed, int ssize, char *sdata)
418 if (ed->slave.bufcmd)
422 if (ssize < (int)sizeof(*scmd)) {
423 ERR("could not read size of command.");
426 ed->slave.bufcmd = malloc(*scmd);
427 ed->slave.scmd = *scmd;
430 return sizeof(*scmd);
434 _ethumbd_slave_data_read_cb(void *data, int type __UNUSED__, void *event)
437 Ecore_Exe_Event_Data *ev = event;
441 if (ev->exe != ed->slave.exe)
443 ERR("PARENT ERROR: slave != ev->exe");
452 if (!ed->slave.bufcmd)
455 n = _ethumbd_slave_alloc_cmd(ed, ssize, sdata);
463 bdata = ed->slave.bufcmd + ed->slave.pcmd;
464 nbytes = ed->slave.scmd - ed->slave.pcmd;
465 nbytes = ssize < nbytes ? ssize : nbytes;
466 memcpy(bdata, sdata, nbytes);
469 ed->slave.pcmd += nbytes;
471 if (ed->slave.pcmd == ed->slave.scmd)
472 _ethumbd_slave_cmd_ready(ed);
480 _ethumbd_slave_del_cb(void *data, int type __UNUSED__, void *event)
483 Ecore_Exe_Event_Del *ev = event;
486 if (ev->exe != ed->slave.exe)
490 ERR("slave exited with code: %d", ev->exit_code);
491 else if (ev->signalled)
492 ERR("slave exited by signal: %d", ev->exit_signal);
497 i = ed->queue.current;
498 ERR("failed to generate thumbnail for: \"%s:%s\"",
499 ed->processing->file, ed->processing->key);
501 if (ed->queue.table[i].used)
502 _ethumb_dbus_generated_signal
503 (ed, &ed->processing->id, NULL, NULL, EINA_FALSE);
504 eina_stringshare_del(ed->processing->file);
505 eina_stringshare_del(ed->processing->key);
506 eina_stringshare_del(ed->processing->thumb);
507 eina_stringshare_del(ed->processing->thumb_key);
508 free(ed->processing);
509 ed->processing = NULL;
512 ed->slave.exe = NULL;
513 if (ed->slave.bufcmd)
514 free(ed->slave.bufcmd);
516 if (!_ethumbd_slave_spawn(&ed->slave, ed))
519 /* restart all queue */
520 for (i = 0; i < ed->queue.count; ++i)
521 _ethumbd_child_write_op_new(&ed->slave, ed->queue.list[i]);
527 _ethumbd_pipe_write_setup(Ethumbd_Slave *slave, int type, const void *data)
530 const float *f_value;
532 _ethumbd_write_safe(slave, &type, sizeof(type));
539 case ETHUMBD_ORIENTATION:
540 case ETHUMBD_QUALITY:
541 case ETHUMBD_COMPRESS:
544 case ETHUMBD_DOCUMENT_PAGE:
545 case ETHUMBD_VIDEO_NTIMES:
546 case ETHUMBD_VIDEO_FPS:
548 _ethumbd_write_safe(slave, i_value, sizeof(*i_value));
552 case ETHUMBD_VIDEO_TIME:
553 case ETHUMBD_VIDEO_START:
554 case ETHUMBD_VIDEO_INTERVAL:
556 _ethumbd_write_safe(slave, f_value, sizeof(*f_value));
558 case ETHUMBD_DIRECTORY:
559 case ETHUMBD_CATEGORY:
560 case ETHUMBD_FRAME_FILE:
561 case ETHUMBD_FRAME_GROUP:
562 case ETHUMBD_FRAME_SWALLOW:
563 _ethumbd_pipe_str_write(slave, data);
565 case ETHUMBD_SETUP_FINISHED:
568 ERR("wrong ethumb setup parameter.");
573 _process_setup(Ethumbd *ed)
575 int op_id = ETHUMBD_OP_SETUP;
576 int idx = ed->queue.current;
578 Ethumbd_Setup *setup = &ed->processing->setup;
579 Ethumbd_Slave *slave = &ed->slave;
581 _ethumbd_write_safe(slave, &op_id, sizeof(op_id));
582 _ethumbd_write_safe(slave, &idx, sizeof(idx));
584 if (setup->flags.fdo)
585 _ethumbd_pipe_write_setup(slave, ETHUMBD_FDO, &setup->fdo);
586 if (setup->flags.size)
588 _ethumbd_pipe_write_setup(slave, ETHUMBD_SIZE_W, &setup->tw);
589 _ethumbd_pipe_write_setup(slave, ETHUMBD_SIZE_H, &setup->th);
591 if (setup->flags.format)
592 _ethumbd_pipe_write_setup(slave, ETHUMBD_FORMAT, &setup->format);
593 if (setup->flags.aspect)
594 _ethumbd_pipe_write_setup(slave, ETHUMBD_ASPECT, &setup->aspect);
595 if (setup->flags.orientation)
596 _ethumbd_pipe_write_setup(slave, ETHUMBD_ORIENTATION, &setup->orientation);
597 if (setup->flags.crop)
599 _ethumbd_pipe_write_setup(slave, ETHUMBD_CROP_X, &setup->cx);
600 _ethumbd_pipe_write_setup(slave, ETHUMBD_CROP_Y, &setup->cy);
602 if (setup->flags.quality)
603 _ethumbd_pipe_write_setup(slave, ETHUMBD_QUALITY, &setup->quality);
604 if (setup->flags.compress)
605 _ethumbd_pipe_write_setup(slave, ETHUMBD_COMPRESS, &setup->compress);
606 if (setup->flags.directory)
607 _ethumbd_pipe_write_setup(slave, ETHUMBD_DIRECTORY, setup->directory);
608 if (setup->flags.category)
609 _ethumbd_pipe_write_setup(slave, ETHUMBD_CATEGORY, setup->category);
610 if (setup->flags.frame)
612 _ethumbd_pipe_write_setup(slave, ETHUMBD_FRAME_FILE, setup->theme_file);
613 _ethumbd_pipe_write_setup(slave, ETHUMBD_FRAME_GROUP, setup->group);
614 _ethumbd_pipe_write_setup(slave, ETHUMBD_FRAME_SWALLOW, setup->swallow);
616 if (setup->flags.video_time)
617 _ethumbd_pipe_write_setup(slave, ETHUMBD_VIDEO_TIME, &setup->video_time);
618 if (setup->flags.video_start)
619 _ethumbd_pipe_write_setup(slave, ETHUMBD_VIDEO_START, &setup->video_start);
620 if (setup->flags.video_interval)
621 _ethumbd_pipe_write_setup(slave, ETHUMBD_VIDEO_INTERVAL,
622 &setup->video_interval);
623 if (setup->flags.video_ntimes)
624 _ethumbd_pipe_write_setup(slave, ETHUMBD_VIDEO_NTIMES, &setup->video_ntimes);
625 if (setup->flags.video_fps)
626 _ethumbd_pipe_write_setup(slave, ETHUMBD_VIDEO_FPS, &setup->video_fps);
627 if (setup->flags.document_page)
628 _ethumbd_pipe_write_setup(slave, ETHUMBD_DOCUMENT_PAGE,
629 &setup->document_page);
630 _ethumbd_pipe_write_setup(slave, ETHUMBD_SETUP_FINISHED, NULL);
633 if (setup->directory) eina_stringshare_del(setup->directory);
634 if (setup->category) eina_stringshare_del(setup->category);
635 if (setup->theme_file) eina_stringshare_del(setup->theme_file);
636 if (setup->group) eina_stringshare_del(setup->group);
637 if (setup->swallow) eina_stringshare_del(setup->swallow);
639 free(ed->processing);
640 ed->processing = NULL;
644 _process_file(Ethumbd *ed)
646 _ethumbd_child_write_op_generate
647 (&ed->slave, ed->queue.current, ed->processing->file,
648 ed->processing->key, ed->processing->thumb, ed->processing->thumb_key);
652 _get_next_on_queue(Ethumbd_Queue *queue)
655 Ethumbd_Object *eobject;
659 if (i >= queue->count)
662 idx = queue->list[i];
663 eobject = &(queue->table[idx]);
664 while (!eobject->nqueue)
666 i = (i + 1) % queue->count;
668 idx = queue->list[i];
669 eobject = &(queue->table[idx]);
672 return queue->list[i];
676 _process_queue_cb(void *data)
678 Ethumbd_Object *eobject;
681 Ethumbd_Queue *queue = &ed->queue;
682 Ethumbd_Request *request;
691 _ethumbd_timeout_start(ed);
696 i = _get_next_on_queue(queue);
697 eobject = &(queue->table[i]);
699 request = eina_list_data_get(eobject->queue);
700 eobject->queue = eina_list_remove_list(eobject->queue, eobject->queue);
701 ed->queue.current = i;
702 DBG("processing file: \"%s:%s\"...", request->file,
704 ed->processing = request;
711 _ethumb_dbus_inc_min_id(eobject);
722 _process_queue_start(Ethumbd *ed)
725 ed->idler = ecore_idler_add(_process_queue_cb, ed);
729 _process_queue_stop(Ethumbd *ed)
733 ecore_idler_del(ed->idler);
739 _ethumb_table_append(Ethumbd *ed)
743 Ethumbd_Queue *q = &ed->queue;
745 if (q->count == q->max_count)
747 int new_max = q->max_count + 5;
751 start = q->max_count;
752 size = new_max - q->max_count;
754 tmp = realloc(q->table, new_max * sizeof(Ethumbd_Object));
757 CRIT("could not realloc q->table to %zd bytes: %s",
758 new_max * sizeof(Ethumbd_Object), strerror(errno));
762 memset(&q->table[start], 0, size * sizeof(Ethumbd_Object));
764 tmp = realloc(q->list, new_max * sizeof(int));
767 CRIT("could not realloc q->list to %zd bytes: %s",
768 new_max * sizeof(int), strerror(errno));
773 q->max_count = new_max;
776 for (i = 0; i < q->max_count; i++)
778 if (!q->table[i].used)
782 snprintf(buf, sizeof(buf), "%s/%d", _ethumb_dbus_path, i);
783 q->table[i].used = 1;
784 q->table[i].path = eina_stringshare_add(buf);
785 q->table[i].max_id = -1;
786 q->table[i].min_id = -1;
787 q->list[q->count] = i;
789 DBG("new object: %s, idx = %d, count = %d", buf, i, q->count);
795 _get_idx_for_path(const char *path)
799 n = sscanf(path, "/org/enlightenment/Ethumb/%d", &i);
806 _ethumb_table_del(Ethumbd *ed, int i)
811 Ethumbd_Queue *q = &ed->queue;
812 Ethumbd_Object_Data *odata;
814 eina_stringshare_del(q->table[i].path);
816 l = q->table[i].queue;
819 Ethumbd_Request *request = l->data;
820 eina_stringshare_del(request->file);
821 eina_stringshare_del(request->key);
822 eina_stringshare_del(request->thumb);
823 eina_stringshare_del(request->thumb_key);
825 l = eina_list_remove_list(l, l);
827 q->nqueue -= q->table[i].nqueue;
829 il = e_dbus_object_interfaces_get(q->table[i].dbus_obj);
832 e_dbus_object_interface_detach(q->table[i].dbus_obj, il->data);
833 il = e_dbus_object_interfaces_get(q->table[i].dbus_obj);
835 odata = e_dbus_object_data_get(q->table[i].dbus_obj);
837 e_dbus_object_free(q->table[i].dbus_obj);
839 memset(&(q->table[i]), 0, sizeof(Ethumbd_Object));
840 for (j = 0; j < q->count; j++)
843 q->list[j] = q->list[q->count - 1];
847 _ethumbd_child_write_op_del(&ed->slave, i);
848 if (!q->count && !ed->processing)
849 _ethumbd_timeout_start(ed);
853 _ethumb_table_clear(Ethumbd *ed)
857 for (i = 0; i < ed->queue.max_count; i++)
858 if (ed->queue.table[i].used)
859 _ethumb_table_del(ed, i);
863 _name_owner_changed_cb(void *data, DBusMessage *msg)
867 Ethumbd_Queue *q = &ed->queue;
868 const char *name, *from, *to;
871 dbus_error_init(&err);
872 if (!dbus_message_get_args(msg, &err,
873 DBUS_TYPE_STRING, &name,
874 DBUS_TYPE_STRING, &from,
875 DBUS_TYPE_STRING, &to,
878 ERR("could not get NameOwnerChanged arguments: %s: %s",
879 err.name, err.message);
880 dbus_error_free(&err);
884 DBG("NameOwnerChanged: name = %s, from = %s, to = %s", name, from, to);
886 if (from[0] == '\0' || to[0] != '\0')
889 from = eina_stringshare_add(from);
890 for (i = 0; i < q->max_count; i++)
892 if (q->table[i].used && q->table[i].client == from)
894 _ethumb_table_del(ed, i);
895 DBG("deleting [%d] from queue table.", i);
901 _ethumb_dbus_add_name_owner_changed_cb(Ethumbd *ed)
903 ed->name_owner_changed_handler = e_dbus_signal_handler_add
904 (ed->conn, fdo_bus_name, fdo_path, fdo_interface, "NameOwnerChanged",
905 _name_owner_changed_cb, ed);
909 _ethumb_dbus_ethumb_new_cb(E_DBus_Object *object, DBusMessage *msg)
912 DBusMessageIter iter;
913 E_DBus_Object *dbus_object;
914 Ethumbd_Object_Data *odata;
916 const char *return_path = "";
920 ed = e_dbus_object_data_get(object);
921 client = dbus_message_get_sender(msg);
925 i = _ethumb_table_append(ed);
929 odata = calloc(1, sizeof(*odata));
933 ed->queue.table[i].client = eina_stringshare_add(client);
934 return_path = ed->queue.table[i].path;
936 dbus_object = e_dbus_object_add(ed->conn, return_path, odata);
939 ERR("could not create dbus_object.");
945 e_dbus_object_interface_attach(dbus_object, ed->objects_iface);
946 ed->queue.table[i].dbus_obj = dbus_object;
948 _ethumbd_child_write_op_new(&ed->slave, i);
949 _ethumbd_timeout_stop(ed);
952 reply = dbus_message_new_method_return(msg);
953 dbus_message_iter_init_append(reply, &iter);
954 dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
959 static struct _Ethumb_DBus_Method_Table _ethumb_dbus_methods[] =
961 {"new", "", "o", _ethumb_dbus_ethumb_new_cb},
962 {NULL, NULL, NULL, NULL}
966 _ethumb_dbus_get_bytearray(DBusMessageIter *iter)
970 DBusMessageIter riter;
973 el_type = dbus_message_iter_get_element_type(iter);
974 if (el_type != DBUS_TYPE_BYTE)
976 ERR("not an byte array element.");
980 dbus_message_iter_recurse(iter, &riter);
981 dbus_message_iter_get_fixed_array(&riter, &result, &length);
983 if ((length == 0) || (result[0] == '\0'))
986 return eina_stringshare_add_length(result, length);
990 _ethumb_dbus_append_bytearray(DBusMessageIter *iter, const char *string)
992 DBusMessageIter viter;
997 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &viter);
998 dbus_message_iter_append_fixed_array
999 (&viter, DBUS_TYPE_BYTE, &string, strlen(string) + 1);
1000 dbus_message_iter_close_container(iter, &viter);
1004 _ethumb_dbus_queue_add_cb(E_DBus_Object *object, DBusMessage *msg)
1007 DBusMessageIter iter;
1008 const char *file, *key;
1009 const char *thumb, *thumb_key;
1010 Ethumbd_Object_Data *odata;
1011 Ethumbd_Object *eobject;
1013 Ethumbd_Request *request;
1014 dbus_int32_t id = -1;
1016 dbus_message_iter_init(msg, &iter);
1017 dbus_message_iter_get_basic(&iter, &id);
1018 dbus_message_iter_next(&iter);
1019 file = _ethumb_dbus_get_bytearray(&iter);
1020 dbus_message_iter_next(&iter);
1021 key = _ethumb_dbus_get_bytearray(&iter);
1022 dbus_message_iter_next(&iter);
1023 thumb = _ethumb_dbus_get_bytearray(&iter);
1024 dbus_message_iter_next(&iter);
1025 thumb_key = _ethumb_dbus_get_bytearray(&iter);
1029 ERR("no filename given.");
1033 odata = e_dbus_object_data_get(object);
1036 ERR("could not get dbus_object data.");
1041 eobject = &(ed->queue.table[odata->idx]);
1042 if (!_ethumb_dbus_check_id(eobject, id))
1044 request = calloc(1, sizeof(*request));
1046 request->file = file;
1048 request->thumb = thumb;
1049 request->thumb_key = thumb_key;
1050 eobject->queue = eina_list_append(eobject->queue, request);
1053 _ethumb_dbus_inc_max_id(eobject, id);
1055 _process_queue_start(ed);
1058 reply = dbus_message_new_method_return(msg);
1059 dbus_message_iter_init_append(reply, &iter);
1060 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &id);
1065 _ethumb_dbus_queue_remove_cb(E_DBus_Object *object, DBusMessage *msg)
1068 DBusMessageIter iter;
1070 Ethumbd_Object_Data *odata;
1071 Ethumbd_Object *eobject;
1072 Ethumbd_Request *request;
1077 dbus_message_iter_init(msg, &iter);
1078 dbus_message_iter_get_basic(&iter, &id);
1080 odata = e_dbus_object_data_get(object);
1083 ERR("could not get dbus_object data.");
1088 eobject = &ed->queue.table[odata->idx];
1093 if (id == request->id)
1101 eina_stringshare_del(request->file);
1102 eina_stringshare_del(request->key);
1103 eina_stringshare_del(request->thumb);
1104 eina_stringshare_del(request->thumb_key);
1106 eobject->queue = eina_list_remove_list(eobject->queue, l);
1109 _ethumb_dbus_inc_min_id(eobject);
1113 reply = dbus_message_new_method_return(msg);
1114 dbus_message_iter_init_append(reply, &iter);
1115 dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &r);
1120 _ethumb_dbus_queue_clear_cb(E_DBus_Object *object, DBusMessage *msg)
1123 Ethumbd_Object_Data *odata;
1124 Ethumbd_Object *eobject;
1128 odata = e_dbus_object_data_get(object);
1131 ERR("could not get dbus_object data.");
1136 eobject = &ed->queue.table[odata->idx];
1140 Ethumbd_Request *request = l->data;
1141 eina_stringshare_del(request->file);
1142 eina_stringshare_del(request->key);
1143 eina_stringshare_del(request->thumb);
1144 eina_stringshare_del(request->thumb_key);
1146 l = eina_list_remove_list(l, l);
1148 ed->queue.nqueue -= eobject->nqueue;
1149 eobject->nqueue = 0;
1152 reply = dbus_message_new_method_return(msg);
1157 _ethumb_dbus_delete_cb(E_DBus_Object *object, DBusMessage *msg)
1160 DBusMessageIter iter;
1161 Ethumbd_Object_Data *odata;
1164 dbus_message_iter_init(msg, &iter);
1165 reply = dbus_message_new_method_return(msg);
1167 odata = e_dbus_object_data_get(object);
1170 ERR("could not get dbus_object data for del_cb.");
1174 _ethumb_table_del(ed, odata->idx);
1181 _ethumb_dbus_fdo_set(Ethumbd_Object *eobject __UNUSED__, DBusMessageIter *iter, Ethumbd_Request *request)
1186 type = dbus_message_iter_get_arg_type(iter);
1187 if (type != DBUS_TYPE_INT32)
1189 ERR("invalid param for fdo_set.");
1193 dbus_message_iter_get_basic(iter, &fdo);
1194 DBG("setting fdo to: %d", fdo);
1195 request->setup.flags.fdo = 1;
1196 request->setup.fdo = fdo;
1202 _ethumb_dbus_size_set(Ethumbd_Object *eobject __UNUSED__, DBusMessageIter *iter, Ethumbd_Request *request)
1204 DBusMessageIter oiter;
1208 type = dbus_message_iter_get_arg_type(iter);
1209 if (type != DBUS_TYPE_STRUCT)
1211 ERR("invalid param for size_set.");
1215 dbus_message_iter_recurse(iter, &oiter);
1216 dbus_message_iter_get_basic(&oiter, &w);
1217 dbus_message_iter_next(&oiter);
1218 dbus_message_iter_get_basic(&oiter, &h);
1219 DBG("setting size to: %dx%d", w, h);
1220 request->setup.flags.size = 1;
1221 request->setup.tw = w;
1222 request->setup.th = h;
1228 _ethumb_dbus_format_set(Ethumbd_Object *eobject __UNUSED__, DBusMessageIter *iter, Ethumbd_Request *request)
1231 dbus_int32_t format;
1233 type = dbus_message_iter_get_arg_type(iter);
1234 if (type != DBUS_TYPE_INT32)
1236 ERR("invalid param for format_set.");
1240 dbus_message_iter_get_basic(iter, &format);
1241 DBG("setting format to: %d", format);
1242 request->setup.flags.format = 1;
1243 request->setup.format = format;
1249 _ethumb_dbus_aspect_set(Ethumbd_Object *eobject __UNUSED__, DBusMessageIter *iter, Ethumbd_Request *request)
1252 dbus_int32_t aspect;
1254 type = dbus_message_iter_get_arg_type(iter);
1255 if (type != DBUS_TYPE_INT32)
1257 ERR("invalid param for aspect_set.");
1261 dbus_message_iter_get_basic(iter, &aspect);
1262 DBG("setting aspect to: %d", aspect);
1263 request->setup.flags.aspect = 1;
1264 request->setup.aspect = aspect;
1270 _ethumb_dbus_orientation_set(Ethumbd_Object *eobject __UNUSED__, DBusMessageIter *iter, Ethumbd_Request *request)
1273 dbus_int32_t orientation;
1275 type = dbus_message_iter_get_arg_type(iter);
1276 if (type != DBUS_TYPE_INT32)
1278 ERR("invalid param for orientation_set.");
1282 dbus_message_iter_get_basic(iter, &orientation);
1283 DBG("setting orientation to: %d", orientation);
1284 request->setup.flags.orientation = 1;
1285 request->setup.orientation = orientation;
1291 _ethumb_dbus_crop_set(Ethumbd_Object *eobject __UNUSED__, DBusMessageIter *iter, Ethumbd_Request *request)
1293 DBusMessageIter oiter;
1297 type = dbus_message_iter_get_arg_type(iter);
1298 if (type != DBUS_TYPE_STRUCT)
1300 ERR("invalid param for crop_set.");
1304 dbus_message_iter_recurse(iter, &oiter);
1305 dbus_message_iter_get_basic(&oiter, &x);
1306 dbus_message_iter_next(&oiter);
1307 dbus_message_iter_get_basic(&oiter, &y);
1308 DBG("setting crop to: %3.2f,%3.2f", x, y);
1309 request->setup.flags.crop = 1;
1310 request->setup.cx = x;
1311 request->setup.cy = y;
1317 _ethumb_dbus_quality_set(Ethumbd_Object *eobject __UNUSED__, DBusMessageIter *iter, Ethumbd_Request *request)
1320 dbus_int32_t quality;
1322 type = dbus_message_iter_get_arg_type(iter);
1323 if (type != DBUS_TYPE_INT32)
1325 ERR("invalid param for quality_set.");
1329 dbus_message_iter_get_basic(iter, &quality);
1330 DBG("setting quality to: %d", quality);
1331 request->setup.flags.quality = 1;
1332 request->setup.quality = quality;
1339 _ethumb_dbus_compress_set(Ethumbd_Object *eobject __UNUSED__, DBusMessageIter *iter, Ethumbd_Request *request)
1342 dbus_int32_t compress;
1344 type = dbus_message_iter_get_arg_type(iter);
1345 if (type != DBUS_TYPE_INT32)
1347 ERR("invalid param for compress_set.");
1351 dbus_message_iter_get_basic(iter, &compress);
1352 DBG("setting compress to: %d", compress);
1353 request->setup.flags.compress = 1;
1354 request->setup.compress = compress;
1360 _ethumb_dbus_frame_set(Ethumbd_Object *eobject __UNUSED__, DBusMessageIter *iter, Ethumbd_Request *request)
1362 DBusMessageIter oiter;
1364 const char *file, *group, *swallow;
1366 type = dbus_message_iter_get_arg_type(iter);
1367 if (type != DBUS_TYPE_STRUCT)
1369 ERR("invalid param for frame_set.");
1373 dbus_message_iter_recurse(iter, &oiter);
1374 file = _ethumb_dbus_get_bytearray(&oiter);
1375 dbus_message_iter_next(&oiter);
1376 group = _ethumb_dbus_get_bytearray(&oiter);
1377 dbus_message_iter_next(&oiter);
1378 swallow = _ethumb_dbus_get_bytearray(&oiter);
1379 DBG("setting frame to \"%s:%s:%s\"", file, group, swallow);
1380 request->setup.flags.frame = 1;
1381 request->setup.theme_file = eina_stringshare_add(file);
1382 request->setup.group = eina_stringshare_add(group);
1383 request->setup.swallow = eina_stringshare_add(swallow);
1389 _ethumb_dbus_directory_set(Ethumbd_Object *eobject __UNUSED__, DBusMessageIter *iter, Ethumbd_Request *request)
1392 const char *directory;
1394 type = dbus_message_iter_get_arg_type(iter);
1395 if (type != DBUS_TYPE_ARRAY)
1397 ERR("invalid param for dir_path_set.");
1401 directory = _ethumb_dbus_get_bytearray(iter);
1402 DBG("setting directory to: %s", directory);
1403 request->setup.flags.directory = 1;
1404 request->setup.directory = eina_stringshare_add(directory);
1410 _ethumb_dbus_category_set(Ethumbd_Object *eobject __UNUSED__, DBusMessageIter *iter, Ethumbd_Request *request)
1413 const char *category;
1415 type = dbus_message_iter_get_arg_type(iter);
1416 if (type != DBUS_TYPE_ARRAY)
1418 ERR("invalid param for category.");
1422 category = _ethumb_dbus_get_bytearray(iter);
1423 DBG("setting category to: %s", category);
1424 request->setup.flags.category = 1;
1425 request->setup.category = eina_stringshare_add(category);
1431 _ethumb_dbus_video_time_set(Ethumbd_Object *eobject __UNUSED__, DBusMessageIter *iter, Ethumbd_Request *request)
1436 type = dbus_message_iter_get_arg_type(iter);
1437 if (type != DBUS_TYPE_DOUBLE)
1439 ERR("invalid param for video_time_set.");
1443 dbus_message_iter_get_basic(iter, &video_time);
1444 DBG("setting video_time to: %3.2f", video_time);
1445 request->setup.flags.video_time = 1;
1446 request->setup.video_time = video_time;
1452 _ethumb_dbus_video_start_set(Ethumbd_Object *eobject __UNUSED__, DBusMessageIter *iter, Ethumbd_Request *request)
1457 type = dbus_message_iter_get_arg_type(iter);
1458 if (type != DBUS_TYPE_DOUBLE)
1460 ERR("invalid param for video_start_set.");
1464 dbus_message_iter_get_basic(iter, &video_start);
1465 DBG("setting video_start to: %3.2f", video_start);
1466 request->setup.flags.video_start = 1;
1467 request->setup.video_start = video_start;
1473 _ethumb_dbus_video_interval_set(Ethumbd_Object *eobject __UNUSED__, DBusMessageIter *iter, Ethumbd_Request *request)
1476 double video_interval;
1478 type = dbus_message_iter_get_arg_type(iter);
1479 if (type != DBUS_TYPE_DOUBLE)
1481 ERR("invalid param for video_interval_set.");
1485 dbus_message_iter_get_basic(iter, &video_interval);
1486 DBG("setting video_interval to: %3.2f", video_interval);
1487 request->setup.flags.video_interval = 1;
1488 request->setup.video_interval = video_interval;
1494 _ethumb_dbus_video_ntimes_set(Ethumbd_Object *eobject __UNUSED__, DBusMessageIter *iter, Ethumbd_Request *request)
1497 unsigned int video_ntimes;
1499 type = dbus_message_iter_get_arg_type(iter);
1500 if (type != DBUS_TYPE_UINT32)
1502 ERR("invalid param for video_ntimes_set.");
1506 dbus_message_iter_get_basic(iter, &video_ntimes);
1507 DBG("setting video_ntimes to: %3.2d", video_ntimes);
1508 request->setup.flags.video_ntimes = 1;
1509 request->setup.video_ntimes = video_ntimes;
1515 _ethumb_dbus_video_fps_set(Ethumbd_Object *eobject __UNUSED__, DBusMessageIter *iter, Ethumbd_Request *request)
1518 unsigned int video_fps;
1520 type = dbus_message_iter_get_arg_type(iter);
1521 if (type != DBUS_TYPE_UINT32)
1523 ERR("invalid param for video_fps_set.");
1527 dbus_message_iter_get_basic(iter, &video_fps);
1528 DBG("setting video_fps to: %3.2d", video_fps);
1529 request->setup.flags.video_fps = 1;
1530 request->setup.video_fps = video_fps;
1536 _ethumb_dbus_document_page_set(Ethumbd_Object *eobject __UNUSED__, DBusMessageIter *iter, Ethumbd_Request *request)
1539 unsigned int document_page;
1541 type = dbus_message_iter_get_arg_type(iter);
1542 if (type != DBUS_TYPE_UINT32)
1544 ERR("invalid param for document_page_set.");
1548 dbus_message_iter_get_basic(iter, &document_page);
1549 DBG("setting document_page to: %d", document_page);
1550 request->setup.flags.document_page = 1;
1551 request->setup.document_page = document_page;
1559 int (*setup_func)(Ethumbd_Object *eobject, DBusMessageIter *iter, Ethumbd_Request *request);
1561 {"fdo", _ethumb_dbus_fdo_set},
1562 {"size", _ethumb_dbus_size_set},
1563 {"format", _ethumb_dbus_format_set},
1564 {"aspect", _ethumb_dbus_aspect_set},
1565 {"orientation", _ethumb_dbus_orientation_set},
1566 {"crop", _ethumb_dbus_crop_set},
1567 {"quality", _ethumb_dbus_quality_set},
1568 {"compress", _ethumb_dbus_compress_set},
1569 {"frame", _ethumb_dbus_frame_set},
1570 {"directory", _ethumb_dbus_directory_set},
1571 {"category", _ethumb_dbus_category_set},
1572 {"video_time", _ethumb_dbus_video_time_set},
1573 {"video_start", _ethumb_dbus_video_start_set},
1574 {"video_interval", _ethumb_dbus_video_interval_set},
1575 {"video_ntimes", _ethumb_dbus_video_ntimes_set},
1576 {"video_fps", _ethumb_dbus_video_fps_set},
1577 {"document_page", _ethumb_dbus_document_page_set},
1582 _ethumb_dbus_ethumb_setup_parse_element(Ethumbd_Object *eobject, DBusMessageIter *iter, Ethumbd_Request *request)
1584 DBusMessageIter viter, diter;
1588 dbus_message_iter_recurse(iter, &diter);
1589 dbus_message_iter_get_basic(&diter, &option);
1590 dbus_message_iter_next(&diter);
1593 for (i = 0; _option_cbs[i].option; i++)
1594 if (!strcmp(_option_cbs[i].option, option))
1602 ERR("ethumb_setup invalid option: %s", option);
1606 dbus_message_iter_recurse(&diter, &viter);
1607 return _option_cbs[i].setup_func(eobject, &viter, request);
1611 _ethumb_dbus_ethumb_setup_cb(E_DBus_Object *object, DBusMessage *msg)
1614 DBusMessageIter iter, aiter;
1615 Ethumbd_Object_Data *odata;
1617 Ethumbd_Object *eobject;
1618 Ethumbd_Request *request;
1622 dbus_message_iter_init(msg, &iter);
1623 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1625 ERR("wrong parameters.");
1629 odata = e_dbus_object_data_get(object);
1632 ERR("could not get dbus_object data for setup_cb.");
1637 eobject = &ed->queue.table[odata->idx];
1639 request = calloc(1, sizeof(*request));
1641 dbus_message_iter_recurse(&iter, &aiter);
1642 atype = dbus_message_iter_get_arg_type(&aiter);
1645 while (atype != DBUS_TYPE_INVALID)
1647 if (!_ethumb_dbus_ethumb_setup_parse_element(eobject, &aiter, request))
1649 dbus_message_iter_next(&aiter);
1650 atype = dbus_message_iter_get_arg_type(&aiter);
1653 eobject->queue = eina_list_append(eobject->queue, request);
1658 reply = dbus_message_new_method_return(msg);
1659 dbus_message_iter_init_append(reply, &iter);
1660 dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &r);
1666 _ethumb_dbus_generated_signal(Ethumbd *ed, int *id, const char *thumb_path, const char *thumb_key, Eina_Bool success)
1671 DBusMessageIter iter;
1678 current = ed->queue.current;
1679 opath = ed->queue.table[current].path;
1680 sig = dbus_message_new_signal
1681 (opath, _ethumb_dbus_objects_interface, "generated");
1683 dbus_message_iter_init_append(sig, &iter);
1684 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &id32);
1685 _ethumb_dbus_append_bytearray(&iter, thumb_path);
1686 _ethumb_dbus_append_bytearray(&iter, thumb_key);
1687 dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &value);
1689 e_dbus_message_send(ed->conn, sig, NULL, -1, NULL);
1690 dbus_message_unref(sig);
1693 static struct _Ethumb_DBus_Method_Table _ethumb_dbus_objects_methods[] = {
1694 {"queue_add", "iayayayay", "i", _ethumb_dbus_queue_add_cb},
1695 {"queue_remove", "i", "b", _ethumb_dbus_queue_remove_cb},
1696 {"clear_queue", "", "", _ethumb_dbus_queue_clear_cb},
1697 {"ethumb_setup", "a{sv}", "b", _ethumb_dbus_ethumb_setup_cb},
1698 {"delete", "", "", _ethumb_dbus_delete_cb},
1699 {NULL, NULL, NULL, NULL}
1702 static struct _Ethumb_DBus_Signal_Table _ethumb_dbus_objects_signals[] = {
1703 {"generated", "iayayb"},
1708 _ethumb_dbus_interface_elements_add(E_DBus_Interface *iface, struct _Ethumb_DBus_Method_Table *mtable, struct _Ethumb_DBus_Signal_Table *stable)
1711 while (mtable && mtable[++i].name)
1712 if (!e_dbus_interface_method_add(iface,
1714 mtable[i].signature,
1716 mtable[i].function))
1720 while (stable && stable[++i].name)
1721 if (!e_dbus_interface_signal_add(iface,
1723 stable[i].signature))
1729 _ethumb_dbus_request_name_cb(void *data, DBusMessage *msg __UNUSED__, DBusError *err)
1731 E_DBus_Object *dbus_object;
1735 if (dbus_error_is_set(err))
1737 ERR("request name error: %s", err->message);
1738 dbus_error_free(err);
1739 e_dbus_connection_close(ed->conn);
1743 dbus_object = e_dbus_object_add(ed->conn, _ethumb_dbus_path, ed);
1746 ed->dbus_obj = dbus_object;
1747 ed->eiface = e_dbus_interface_new(_ethumb_dbus_interface);
1750 ERR("could not create interface.");
1753 r = _ethumb_dbus_interface_elements_add(ed->eiface,
1754 _ethumb_dbus_methods, NULL);
1757 ERR("could not add methods to the interface.");
1758 e_dbus_interface_unref(ed->eiface);
1761 e_dbus_object_interface_attach(dbus_object, ed->eiface);
1763 ed->objects_iface = e_dbus_interface_new(_ethumb_dbus_objects_interface);
1764 if (!ed->objects_iface)
1766 ERR("could not create interface.");
1770 r = _ethumb_dbus_interface_elements_add(ed->objects_iface,
1771 _ethumb_dbus_objects_methods,
1772 _ethumb_dbus_objects_signals);
1775 ERR("ERROR: could not setup objects interface methods.");
1776 e_dbus_interface_unref(ed->objects_iface);
1780 _ethumb_dbus_add_name_owner_changed_cb(ed);
1782 _ethumbd_timeout_start(ed);
1786 _ethumb_dbus_setup(Ethumbd *ed)
1789 (ed->conn, _ethumb_dbus_bus_name, 0, _ethumb_dbus_request_name_cb, ed);
1795 _ethumb_dbus_finish(Ethumbd *ed)
1797 _process_queue_stop(ed);
1798 _ethumb_table_clear(ed);
1799 e_dbus_signal_handler_del(ed->conn, ed->name_owner_changed_handler);
1800 e_dbus_interface_unref(ed->objects_iface);
1801 e_dbus_interface_unref(ed->eiface);
1802 e_dbus_object_free(ed->dbus_obj);
1803 free(ed->queue.table);
1804 free(ed->queue.list);
1808 _ethumbd_slave_spawn(Ethumbd_Slave *slave, Ethumbd *ed)
1810 slave->bufcmd = NULL;
1813 slave->exe = ecore_exe_pipe_run(
1814 ETHUMB_LIBEXEC_DIR"/ethumbd_slave",
1815 ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE, ed);
1818 ERR("could not create slave.");
1826 main(int argc, char *argv[])
1828 Eina_Bool quit_option = 0;
1833 double timeout = -1;
1835 memset(&ed, 0, sizeof(ed));
1841 if (_log_domain < 0)
1843 _log_domain = eina_log_domain_register("ethumbd", NULL);
1844 if (_log_domain < 0)
1846 EINA_LOG_CRIT("could not register log domain 'ethumbd'");
1852 ed.data_cb = ecore_event_handler_add(ECORE_EXE_EVENT_DATA,
1853 _ethumbd_slave_data_read_cb, &ed);
1854 ed.del_cb = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
1855 _ethumbd_slave_del_cb, &ed);
1857 child = _ethumbd_slave_spawn(&ed.slave, &ed);
1872 ERR("could not init e_dbus.");
1877 Ecore_Getopt_Value values[] = {
1878 ECORE_GETOPT_VALUE_DOUBLE(timeout),
1879 ECORE_GETOPT_VALUE_BOOL(quit_option),
1880 ECORE_GETOPT_VALUE_BOOL(quit_option),
1881 ECORE_GETOPT_VALUE_BOOL(quit_option),
1882 ECORE_GETOPT_VALUE_BOOL(quit_option),
1883 ECORE_GETOPT_VALUE_NONE
1886 arg_idx = ecore_getopt_parse(&optdesc, values, argc, argv);
1889 ERR("Could not parse arguments.");
1897 ed.conn = e_dbus_bus_get(DBUS_BUS_SESSION);
1900 ERR("could not connect to session bus.");
1905 ed.timeout = timeout;
1907 if (!_ethumb_dbus_setup(&ed))
1909 e_dbus_connection_close(ed.conn);
1910 ERR("could not setup dbus connection.");
1915 ecore_main_loop_begin();
1916 _ethumb_dbus_finish(&ed);
1919 if (_log_domain >= 0)
1921 eina_log_domain_unregister(_log_domain);
1928 ecore_exe_quit(ed.slave.exe);