e3681c180a0446e4bcdc0aeb03fe11d7ae3338df
[apps/home/image-viewer.git] / src / image-viewer.c
1 /*
2  * Copyright 2012  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *        http://www.tizenopensource.org/license
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <stdbool.h>
19
20 #include <Elementary.h>
21 #include <app.h>
22
23 #include <utilX.h>
24 #include <Evas.h>
25 #include <Ecore_X.h>
26
27 #include <ui-gadget-module.h>
28 #include <ui-gadget.h>
29
30 #include <vconf.h>
31 #include <vconf-keys.h>
32
33 #include "image-viewer.h"
34
35 #define PACKAGE "image-viewer"
36 #define LOCALEDIR "/opt/apps/com.image-viewer/res/locale"
37
38 #define UG_MODE_SINGLE "SINGLE"
39 #define UG_STANDALONE_VALUE "TRUE"
40
41 #define UG_BUNDLE_KEY_VIEW_MODE                 "View Mode"
42 #define UG_BUNDLE_KEY_PATH                              "Path"
43 #define UG_BUNDLE_KEY_SETAS_TYPE                "Setas type"
44 #define UG_BUNDLE_KEY_STANDALONE                "Standalone"
45
46 #define SERVICE_OPERATION_CROP "http://tizen.org/appsvc/operation/crop"
47
48 static const char *_conver_error(int err)
49 {
50         switch(err)
51         {
52                 case SERVICE_ERROR_NONE:
53                         return "Successful";
54                 case SERVICE_ERROR_INVALID_PARAMETER:
55                         return "Invalid parameter";
56                 case SERVICE_ERROR_KEY_NOT_FOUND:
57                         return "Specified key not found";
58                 case SERVICE_ERROR_OUT_OF_MEMORY:
59                         return "Out of memory";
60                 case SERVICE_ERROR_INVALID_DATA_TYPE:
61                         return "Invalid data type";
62                 default:
63                 {
64                         static char error[128];
65                         sprintf(error, "Unknow Error : %d(0x%08x)", err, err);
66                         return error;
67                 }
68         }
69         return NULL;
70 }
71
72 void _orient_changed(app_device_orientation_e orientation, void *user_data);
73
74
75 /**
76 * @brief        The win delete function
77 *
78 * @param data
79 * @param obj
80 * @param event_info
81 */
82 static void _win_del(void *data, Evas_Object *obj, void *event_info)
83 {
84         elm_exit();
85 }
86
87
88 /**
89 * @brief        Create the main window
90 *
91 * @param name   The title of the window
92 *
93 * @return  the win on sucess
94 */
95 static Evas_Object* _create_win(const char *name)
96 {
97         iv_retv_if(name == NULL, NULL);
98         Evas_Object *eo;
99         int w, h;
100
101         eo = elm_win_add(NULL, name, ELM_WIN_BASIC);
102         if (eo)
103         {
104                 elm_win_title_set(eo, name);
105                 elm_win_borderless_set(eo, EINA_TRUE);
106                 evas_object_smart_callback_add(eo, "delete,request", _win_del, NULL);
107                 ecore_x_window_size_get(ecore_x_window_root_first_get(),
108                                 &w, &h);
109                 evas_object_resize(eo, w, h);
110         }
111
112         return eo;
113 }
114
115 /**
116 * @brief Create the background
117 *
118 * @param parent object
119 */
120 static Evas_Object* _create_bgimg(Evas_Object* parent)
121 {
122         Evas_Object *bg = elm_bg_add(parent);
123         evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
124         evas_object_size_hint_align_set(bg, EVAS_HINT_FILL, EVAS_HINT_FILL);
125
126         elm_win_resize_object_add(parent, bg);
127
128         evas_object_show(bg);
129
130         return bg;
131 }
132
133 /**
134 * @brief The layout callback after ug created
135 *
136 * @param ug     The ug created
137 * @param mode   The UG mode, FULLVIEW or FRAMEVIEW
138 * @param priv   The privite data
139 */
140 void _ug_layout_cb(ui_gadget_h ug, enum ug_mode mode, void* priv)
141 {
142         IV_MSG_HIGH("ug Layout CB. UG=0x%08x Priv=0x%08x Mode=%d", ug, priv, mode);
143
144         Evas_Object *base, *win;
145
146         if (!ug || !priv)
147         {
148                 IV_MSG_ERROR("Abnormal value. UG=0x%08x Priv=0x%08x Mode=%d", ug, priv, mode);
149                 return;
150         }
151
152         appdata_iv *ap = (appdata_iv *)priv;
153
154         base = ug_get_layout(ug);
155         if (!base)
156         {
157                 IV_MSG_HIGH( "ug_get_layout is fail");
158                 return;
159         }
160         ap->ug_layout = base;
161
162         win = ug_get_window();
163
164         switch (mode)
165         {
166                 case UG_MODE_FULLVIEW:
167                         evas_object_size_hint_weight_set(base, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
168                         elm_win_resize_object_add(win, base);
169                         ug_disable_effect(ug);
170                         evas_object_show(base);
171                         break;
172                 default:
173                         IV_MSG_HIGH("Unknow UG mode : %d", mode);
174                         break;
175         }
176
177 }
178
179 /**
180 * @brief        The return callback on ug send result
181 *
182 * @param ug     The ug created
183 * @param result The result received from ug
184 * @param priv   The privite data
185 */
186 void _ug_result_cb(ui_gadget_h ug, service_h reply, void *priv)
187 {
188         IV_MSG_HIGH("UG Result CB.");
189
190         if (!ug || !priv)
191         {
192                 IV_MSG_ERROR("Abnormal value. UG=0x%08x Priv=0x%08x", ug, priv);
193                 return;
194         }
195
196         appdata_iv *ap = (appdata_iv *)priv;
197
198         int ret = service_reply_to_launch_request(reply, ap->service_handle, SERVICE_RESULT_SUCCEEDED);
199         if (ret != SERVICE_ERROR_NONE)
200         {
201                 IV_MSG_ERROR("service_reply_to_launch_request failed! [%s]", _conver_error(ret));
202         }
203 }
204
205 /**
206 * @brief The close callback on ug destroy
207 *
208 * @param ug     The ug created
209 * @param priv   The privite data
210 */
211 void _ug_closed_cb(ui_gadget_h ug, void *priv)
212 {
213         IV_MSG_HIGH("UG Destroyed..");
214
215         if (!ug || !priv)
216         {
217                 IV_MSG_ERROR("Abnormal value. UG=0x%08x Priv=0x%08x", ug, priv);
218                 return;
219         }
220
221         //appdata_iv *ap = (appdata_iv *)priv;
222
223         elm_exit();             // will tirgger app_terminated
224 }
225
226 /**
227 * @brief        Create the image-viewer-ug
228 *
229 * @param data   The app data
230 *
231 * @return  ug on sucess, NULL on fail
232 */
233 ui_gadget_h _create_ug(void* data)
234 {
235         iv_retv_if(data == NULL, NULL);
236
237         appdata_iv *ap = (appdata_iv *)data;
238
239         ui_gadget_h ug;
240         struct ug_cbs cbs = {0,};
241
242         cbs.layout_cb = _ug_layout_cb;
243         cbs.result_cb = _ug_result_cb;
244         cbs.destroy_cb = _ug_closed_cb;
245         cbs.priv = ap;
246
247         ug = ug_create(NULL, "image-viewer-efl", UG_MODE_FULLVIEW, ap->service_handle, &cbs);
248
249         IV_MSG_HIGH("UG Created!");
250         return ug;
251 }
252
253 static bool _is_rotation_lock(void)
254 {
255         int lock = 0;
256         int ret = -1;
257
258         ret = vconf_get_bool(VCONFKEY_SETAPPL_ROTATE_LOCK_BOOL, &lock);
259
260         if ( ret != 0)  // Failed
261         {
262                 IV_MSG_HIGH( "Rotation locked state is [%d].", lock);
263                 return false;
264         }
265
266         if ( lock == true)
267         {
268                 IV_MSG_HIGH("Rotation is locked");
269                 return true;
270         }
271
272         return false;
273 }
274
275 static void _on_portrait_lock_changed(keynode_t* node, void *user_data)
276 {
277         IV_MSG_HIGH("State changed. %s=%d", vconf_keynode_get_name(node), vconf_keynode_get_bool(node));
278
279         if ( vconf_keynode_get_bool(node) == true )
280         {
281                 // When Set portrait lock, Set degree as 0.
282                 _orient_changed(APP_DEVICE_ORIENTATION_0, user_data);
283         }
284 }
285
286 static bool _app_create(void *user_data)
287 {
288 // Hook to take necessary actions before main event loop starts
289 // Initialize UI resources and application's data
290 // If this function returns true, the main loop of application starts
291 // If this function returns false, the application is terminated
292         IV_ASSERT(user_data != NULL);
293
294         IV_MSG_HIGH("App Create");
295
296         elm_config_preferred_engine_set("opengl_x11");  //enabling the OpenGL as the backend of the EFL.
297
298         appdata_iv *ap = (appdata_iv *) user_data;
299
300         Evas_Object *win = _create_win(PACKAGE);
301         if ( win == NULL )
302         {
303                 IV_MSG_ERROR("Cannot create app. pkg=%s", PACKAGE);
304                 return false;
305         }
306
307         ap->win_main = win;
308
309         UG_INIT_EFL(ap->win_main, UG_OPT_INDICATOR_ENABLE);     // Init UG module
310
311         ap->bg = _create_bgimg(ap->win_main);
312         if ( ap->bg == NULL )
313         {
314                 IV_MSG_ERROR("Cannot create bg");
315                 return false;
316         }
317
318         int ret = -1;
319
320         ret = vconf_notify_key_changed(VCONFKEY_SETAPPL_ROTATE_LOCK_BOOL, _on_portrait_lock_changed, user_data);
321         if ( ret == -1 )
322         {
323                 IV_MSG_ERROR("Register %s is failed", VCONFKEY_SETAPPL_ROTATE_LOCK_BOOL);
324                 return false;
325         }
326
327         _orient_changed(app_get_device_orientation(), user_data);               // Set initial degree
328
329         return true;
330 }
331
332 bool _iter_extra_data_cb(service_h service, const char *key, void *user_data)
333 {
334         char *value = NULL;
335
336         IV_MSG_HIGH("  Key=%s Value=%s", key, value);
337
338         int ret = service_get_extra_data(service, key, &value);
339         if (ret != SERVICE_ERROR_NONE)
340         {
341                 IV_MSG_ERROR("service_get_extra_data %s failed, [%s]", key, _conver_error(ret));
342                 return false;
343         }
344
345         free(value);
346
347         return true;
348 }
349
350
351 static void _app_service(service_h service, void *user_data)
352 {
353 // How to get Alarm service????
354         appdata_iv *ap = (appdata_iv *)user_data;
355
356         IV_MSG_HIGH("%s", __func__);
357
358         char *operation = NULL;
359         char *uri = NULL;
360
361         int ret = service_get_operation(service, &operation);
362         if (ret != SERVICE_ERROR_NONE)
363         {
364                 IV_MSG_ERROR("service_get_operation failed, [%s]", _conver_error(ret));
365                 goto EXIT;
366         }
367
368         if ( operation == NULL )
369         {
370                 IV_MSG_ERROR("Operation cannot be NULL.");
371                 goto EXIT;
372         }
373
374         ret = service_foreach_extra_data(service, _iter_extra_data_cb, NULL);
375         if (ret != SERVICE_ERROR_NONE)
376         {
377                 IV_MSG_ERROR("service_foreach_extra_data failed, [%s]", _conver_error(ret));
378                 goto EXIT;
379         }
380
381         ret = service_get_uri(service, &uri);
382         if (ret != SERVICE_ERROR_NONE)
383         {
384                 IV_MSG_ERROR("service_get_uri failed, [%s]", _conver_error(ret));
385                 goto EXIT;
386         }
387
388         IV_MSG_HIGH( "Operation=%s URI=%s", operation, uri);
389
390         ret = service_clone(&ap->service_handle, service);
391         if (ret != SERVICE_ERROR_NONE)
392         {
393                 IV_MSG_ERROR("service_clone failed, [%s]", _conver_error(ret));
394                 goto EXIT;
395         }
396
397         if( strcmp(operation, SERVICE_OPERATION_VIEW) == 0 || strcmp(operation, SERVICE_OPERATION_DEFAULT) == 0)
398         {
399                 if(uri) // uri can entered through argv[1]
400                 {
401                         ap->iv_param_path = uri;
402                 }
403                 if ( ap->iv_param_path == NULL )
404                 {
405                         IV_MSG_ERROR("Entered path is NULL");
406                         goto EXIT;
407                 }
408
409                 IV_MSG_HIGH("*****************************");
410                 IV_MSG_HIGH("com.samsung.image-viewer : Case View");
411                 IV_MSG_HIGH("  URI path  : %s", ap->iv_param_path);
412                 IV_MSG_HIGH("*****************************");
413
414                 free(operation);
415         }
416         else if( strcmp(operation, SERVICE_OPERATION_CROP) == 0)
417         {
418                 char *value = NULL;             // Will freed on terminate
419
420                 if(uri) // uri can entered through argv[1]
421                 {
422                         ap->iv_param_path = uri;
423                 }
424                 if ( ap->iv_param_path == NULL )
425                 {
426                         IV_MSG_ERROR("Entered path is NULL");
427                         goto EXIT;
428                 }
429
430                 service_add_extra_data(ap->service_handle, UG_BUNDLE_KEY_VIEW_MODE, "SETAS");
431
432                 service_get_extra_data(ap->service_handle, UG_BUNDLE_KEY_SETAS_TYPE, &value);
433                 if(value == NULL)
434                 {
435                         service_add_extra_data(ap->service_handle, UG_BUNDLE_KEY_SETAS_TYPE, "Crop");
436                 }
437
438                 IV_MSG_HIGH("*****************************");
439                 IV_MSG_HIGH("com.samsung.image-viewer : Case Crop");
440                 IV_MSG_HIGH("  URI path  : %s", ap->iv_param_path);
441                 IV_MSG_HIGH("*****************************");
442
443                 free(operation);
444         }
445         else
446         {
447                 IV_MSG_ERROR("Unknown operation. %s", operation);
448                 free(operation);
449
450                 if ( ap->iv_param_path == NULL )
451                 {
452                         IV_MSG_ERROR("Entered path is NULL");
453                         goto EXIT;
454                 }
455         }
456
457         if(ap->iv_param_path == NULL)
458         {
459                 IV_MSG_ERROR("File path is NULL. cannot create UG");
460                 goto EXIT;
461         }
462
463         elm_win_activate(ap->win_main);
464         evas_object_show(ap->win_main);
465
466         if(ap->iv_ug != NULL)
467         {
468                 // Create Previous UG if exist
469                 IV_MSG_HIGH("Removing previous UG=0x%08x", ap->iv_ug);
470                 ug_destroy(ap->iv_ug);
471                 ap->iv_ug = NULL;
472         }
473
474         char *view_mode = NULL;
475         service_get_extra_data(ap->service_handle, UG_BUNDLE_KEY_VIEW_MODE, &view_mode);
476         if(view_mode == NULL)
477         {
478                 service_add_extra_data(ap->service_handle, UG_BUNDLE_KEY_VIEW_MODE, UG_MODE_SINGLE);
479         }
480
481         service_add_extra_data(ap->service_handle, UG_BUNDLE_KEY_PATH, ap->iv_param_path);
482
483         service_add_extra_data(ap->service_handle, UG_BUNDLE_KEY_STANDALONE, UG_STANDALONE_VALUE);
484
485         ap->iv_ug = _create_ug(ap);
486         if(ap->iv_ug == NULL)
487         {
488                 IV_MSG_HIGH("create_ug failed. Terminated");
489                 elm_exit();
490                 return;
491         }
492
493         return;
494
495 EXIT:
496         if(ap->service_handle)
497                 service_destroy(ap->service_handle);
498         ap->service_handle = NULL;
499         elm_exit();
500         return;
501
502 }
503
504
505 void _app_pause(void *user_data)
506 {
507 // Take necessary actions when application becomes invisible.
508         IV_MSG_HIGH("%s", __func__);
509
510         ug_pause();
511 }
512
513 void _app_resume(void *user_data)
514 {
515 // Take necessary actions when application becomes visible.
516         IV_MSG_HIGH("%s", __func__);
517
518         ug_resume();
519 }
520
521 void _app_terminate(void *user_data)
522 {
523 // Release all resources
524         IV_MSG_HIGH("%s", __func__);
525
526         appdata_iv *ap = (appdata_iv *)user_data;
527
528         if(ap->service_handle) {
529                 service_destroy(ap->service_handle);
530                 ap->service_handle = NULL;
531         }
532
533         if(ap->iv_ug)
534         {
535                 ug_destroy(ap->iv_ug);
536                 ap->iv_ug = NULL;
537         }
538
539         if(ap->ug_layout)
540         {
541                 evas_object_del(ap->ug_layout);
542                 ap->ug_layout = NULL;
543         }
544
545         IV_MSG_HIGH("%s terminated.", __func__);
546 }
547
548 void _region_changed(void *user_data)
549 {
550         IV_MSG_HIGH("%s", __func__);
551         // Not used yet.
552 }
553
554 void _low_battery(void *user_data)
555 {
556         IV_MSG_HIGH("%s", __func__);
557         ug_send_event( UG_EVENT_LOW_BATTERY );
558 }
559
560 void _low_memory(void *user_data)
561 {
562         IV_MSG_HIGH("%s", __func__);
563         ug_send_event( UG_EVENT_LOW_MEMORY );
564
565 }
566
567 void _lang_changed(void *user_data)
568 {
569         IV_MSG_HIGH("%s", __func__);
570         ug_send_event( UG_EVENT_LANG_CHANGE );
571
572 }
573
574 void _orient_changed(app_device_orientation_e orientation, void *user_data)
575 {
576         IV_MSG_HIGH("%s. orientation=%d", __func__, orientation);
577
578 /*
579         enum app_device_orientation_e
580
581         APP_DEVICE_ORIENTATION_0  The device is oriented in natural position
582
583         APP_DEVICE_ORIENTATION_90  The device's left side is at the top
584
585         APP_DEVICE_ORIENTATION_180      The device is upside down
586
587         APP_DEVICE_ORIENTATION_270      The device's right side is to the top
588
589 */
590         appdata_iv *ap = (appdata_iv *)user_data;
591
592         int degree = 0;
593         enum ug_event evt = UG_EVENT_NONE;
594
595         if ( _is_rotation_lock() == true )      // When rotatation lock is set, show application as portrate mode.
596         {
597                 orientation = APP_DEVICE_ORIENTATION_0;
598         }
599
600         switch(orientation)
601         {
602         case APP_DEVICE_ORIENTATION_0:
603                 degree = 0;
604                 evt = UG_EVENT_ROTATE_PORTRAIT;
605                 break;
606         case APP_DEVICE_ORIENTATION_90:
607                 degree = 90;
608                 evt = UG_EVENT_ROTATE_LANDSCAPE_UPSIDEDOWN;
609                 break;
610
611         case APP_DEVICE_ORIENTATION_180:
612                 degree = 180;
613                 evt = UG_EVENT_ROTATE_PORTRAIT_UPSIDEDOWN;
614                 break;
615
616         case APP_DEVICE_ORIENTATION_270:
617                 evt = UG_EVENT_ROTATE_LANDSCAPE;
618                 degree = 270;
619                 break;
620         }
621
622         ug_send_event( evt );
623
624 //      IV_MSG_HIGH( "evt = %d, r = %d", evt, r);
625
626         if ( ap->win_main != NULL )
627         {
628                 elm_win_rotation_with_resize_set(ap->win_main, degree);
629         }
630 }
631
632
633 /**
634 * @brief The main function
635 *
636 * @param argc   The number of arguments
637 * @param argv[] The arguments
638 *
639 * @return 0 on sucess, others on fail
640 */
641 int main(int argc, char *argv[])
642 {
643         //setenv("ELM_ENGINE", "gl", 1); //changed to elm_config_preferred_engine_set("opengl_x11") at _app_create
644
645         appdata_iv ad = {0,};
646
647         app_event_callback_s event_callback = {0,};
648
649         event_callback.create = _app_create;
650         event_callback.terminate = _app_terminate;
651         event_callback.pause = _app_pause;
652         event_callback.resume = _app_resume;
653         event_callback.service = _app_service;
654
655         event_callback.low_memory = _low_memory;
656         event_callback.low_battery = _low_battery;
657         event_callback.device_orientation = _orient_changed;    /* Rotate is not supported in FMRadio */
658         event_callback.language_changed = _lang_changed;                /* Currently, Application will terminated when change language */
659         event_callback.region_format_changed = NULL;
660
661         if ( argc == 2 )                // For command line options.
662         {
663                 IV_MSG_HIGH("Parsing from cmd line. file=%s", argv[1]);
664                 ad.iv_param_path = strdup(argv[1]);
665         }
666
667         int ret = APP_ERROR_NONE;
668
669         ret = app_efl_main(&argc, &argv, &event_callback, &ad);
670
671         if ( ret != APP_ERROR_NONE )
672         {
673                 IV_MSG_ERROR("app_efl_main() is failed. err=%d", ret);
674                 // Go through
675         }
676
677         return ret;
678
679 }
680