1 #include "private.h"
2
3 #include <assert.h>
4 #include <Elementary.h>
5 #include <Elementary_Cursor.h>
6 #include <Ecore_Input.h>
7 #include <Ecore_IMF.h>
8 #include <Ecore_IMF_Evas.h>
9 #include "win.h"
10 #include "termcmd.h"
11 #include "config.h"
12 #include "main.h"
13 #include "miniview.h"
14 #include "gravatar.h"
15 #include "media.h"
16 #include "termio.h"
17 #include "theme.h"
18 #include "sel.h"
19 #include "controls.h"
20 #include "keyin.h"
21 #include "term_container.h"
22
23
24 /**
25 * Design:
26 * A terminal widget is Term. It hosts various Evas_Object, like a `termio`
27 * handling the textgrid.
28 * It is hosted in a Term_Container of type Solo.
29 * On Term_Container:
30 * It is a generic structure with a set of function pointers. It is a simple
31 * way to objectify and have genericity between a Window, a Split or Tabs.
32 * Solo, Win, Split, Tabs have a Term_Container as their first field and thus
33 * can be casted to Term_Container to have access to those APIs.
34 *
35 * Solo is the simplest container, hosting just a Term.
36 * Win is a window and has only one container child.
37 * Split is a widget to separate an area of the screen in 2 and thus has 2
38 * children that can be either Solo or Tabs.
39 * Tabs is a Term_Container containing many containers (at the moment, only
40 * Solo ones) and have a system of tabs.
41 *
42 * All the windows are in the `wins` list.
43 */
44
45
46
47
48 /* specific log domain to help debug code in that file */
49 int _win_log_dom = -1;
50
51 #undef CRITICAL
52 #undef ERR
53 #undef WRN
54 #undef INF
55 #undef DBG
56
57 #define CRITICAL(...) EINA_LOG_DOM_CRIT(_win_log_dom, __VA_ARGS__)
58 #define ERR(...) EINA_LOG_DOM_ERR(_win_log_dom, __VA_ARGS__)
59 #define WRN(...) EINA_LOG_DOM_WARN(_win_log_dom, __VA_ARGS__)
60 #define INF(...) EINA_LOG_DOM_INFO(_win_log_dom, __VA_ARGS__)
61 #define DBG(...) EINA_LOG_DOM_DBG(_win_log_dom, __VA_ARGS__)
62
63 #define PANES_TOP "top"
64 #define PANES_BOTTOM "bottom"
65
66 #define DRAG_TIMEOUT 0.4
67
68 /* {{{ Structs */
69
70 typedef struct _Split Split;
71 typedef struct _Tabbar Tabbar;
72 typedef struct _Solo Solo;
73 typedef struct _Tabs Tabs;
74 typedef struct _Tab_Item Tab_Item;
75 typedef struct _Tab_Drag Tab_Drag;
76
77
78 struct _Tab_Drag
79 {
80 Evas_Coord mdx; /* Mouse-down x */
81 Evas_Coord mdy; /* Mouse-down y */
82 Split_Direction split_direction;
83 Term *term_over;
84 Term *term;
85 Evas_Object *icon;
86 Evas_Object *img;
87 Evas *e;
88 Ecore_Timer *timer;
89 /* To be able to restore */
90 Term_Container_Type parent_type;
91 union {
92 struct {
93 int previous_position;
94 Term_Container *tabs_child;
95 };
96 struct {
97 Term_Container *other;
98 double left_size;
99 Eina_Bool is_horizontal;
100 Eina_Bool is_first_child;
101 }; };
102 };
103
104 struct _Tabbar
105 {
106 struct {
107 Evas_Object *box;
108 } l, r;
109 };
110
111 struct _Term
112 {
113 Win *wn;
114 Config *config;
115
116 Term_Container *container;
117 Evas_Object *bg;
118 Evas_Object *bg_edj;
119 Evas_Object *core;
120 Evas_Object *termio;
121 Evas_Object *media;
122 Evas_Object *popmedia;
123 Evas_Object *miniview;
124 Evas_Object *sel;
125 Evas_Object *sendfile_request;
126 Evas_Object *sendfile_progress;
127 Evas_Object *sendfile_progress_bar;
128 Evas_Object *tab_spacer;
129 Evas_Object *tab_region_base;
130 Evas_Object *tab_region_bg;
131 Evas_Object *tab_inactive;
132 Tab_Item *tab_item;
133 Eina_List *popmedia_queue;
134 Ecore_Timer *sendfile_request_hide_timer;
135 Ecore_Timer *sendfile_progress_hide_timer;
136 const char *sendfile_dir;
137 Media_Type poptype, mediatype;
138 Tabbar tabbar;
139 int step_x, step_y, min_w, min_h, req_w, req_h;
140 struct {
141 int x, y;
142 } down;
143 int refcnt;
144 unsigned char hold : 1;
145 unsigned char unswallowed : 1;
146 unsigned char missed_bell : 1;
147 unsigned char miniview_shown : 1;
148 unsigned char popmedia_deleted : 1;
149 unsigned char has_bg_cursor : 1;
150 unsigned char core_cursor_set: 1;
151
152 Eina_Bool sendfile_request_enabled : 1;
153 Eina_Bool sendfile_progress_enabled : 1;
154 };
155
156 struct _Solo {
157 Term_Container tc;
158 Term *term;
159 };
160
161 struct _Tab_Item {
162 Term_Container *tc;
163 Evas_Object *obj;
164 void *selector_entry;
165 };
166
167 struct _Tabs {
168 Term_Container tc;
169 Evas_Object *selector;
170 Evas_Object *selector_bg;
171 Eina_List *tabs; // Tab_Item
172 Tab_Item *current;
173 double v1_orig;
174 double v2_orig;
175 };
176
177 struct _Split
178 {
179 Term_Container tc;
180 Term_Container *tc1, *tc2; // left/right or top/bottom child splits, null if leaf
181 Evas_Object *panes;
182 Term_Container *last_focus;
183
184 unsigned char is_horizontal : 1;
185 };
186
187
188
189
190 struct _Win
191 {
192 Term_Container tc; /* has to be first field */
193
194 Keys_Handler khdl;
195 const char *preedit_str;
196 Term_Container *child;
197 Evas_Object *win;
198 Evas_Object *conform;
199 Evas_Object *backbg;
200 Evas_Object *base;
201 Config *config;
202 Eina_List *terms;
203 Split *split;
204 Ecore_Job *size_job;
205 Evas_Object *cmdbox;
206 Ecore_Timer *cmdbox_del_timer;
207 Ecore_Timer *hide_cursor_timer;
208 Ecore_Event_Handler *config_elm_handler;
209 unsigned char focused : 1;
210 unsigned char cmdbox_up : 1;
211 unsigned char group_input : 1;
212 unsigned char group_only_visible : 1;
213 unsigned char group_once_handled : 1;
214 unsigned char translucent : 1;
215
216 unsigned int on_popover;
217 };
218
219 /* }}} */
220 /* {{{ static */
221 static Eina_List *wins = NULL;
222 static Tab_Drag *_tab_drag = NULL;
223
224 static Eina_Bool _win_is_focused(Win *wn);
225 static Term_Container *_solo_new(Term *term, Win *wn);
226 static Term_Container *_split_new(Term_Container *tc1, Term_Container *tc2,
227 double left_size, Eina_Bool is_horizontal);
228 static Term_Container *_tabs_new(Term_Container *child, Term_Container *parent);
229 static void _term_free(Term *term);
230 static void _term_media_update(Term *term, const Config *config);
231 static void _term_miniview_check(Term *term);
232 static void _popmedia_queue_process(Term *term);
233 static void _cb_size_hint(void *data, Evas *_e EINA_UNUSED, Evas_Object *obj, void *_event EINA_UNUSED);
234 static void _tab_new_cb(void *data, Evas_Object *_obj EINA_UNUSED, void *_event_info EINA_UNUSED);
235 static Tab_Item* tab_item_new(Tabs *tabs, Term_Container *child);
236 static void _tabs_recreate(Tabs *tabs);
237 static void _tab_drag_free(void);
238 static void _term_tabregion_free(Term *term);
239 static void _imf_event_commit_cb(void *data, Ecore_IMF_Context *_ctx EINA_UNUSED, void *event);
240
241 /* }}} */
242 /* {{{ Utils */
243 #ifndef NDEBUG
244 static void
_focus_validator(void)245 _focus_validator(void)
246 {
247 Win *wn;
248 Term *term;
249 Eina_List *l, *ll;
250
251 EINA_LIST_FOREACH(wins, l, wn)
252 {
253 Term_Container *focused_found = NULL;
254
255 if (wn->group_input)
256 continue;
257
258 EINA_LIST_FOREACH(wn->terms, ll, term)
259 {
260 Term_Container *tc = term->container;
261
262 if (focused_found)
263 {
264 assert(!tc->is_focused);
265 }
266 else
267 {
268 if (tc->is_focused)
269 {
270 Term *term_focused;
271 Term_Container *tc_parent = tc;
272
273 focused_found = tc;
274 do
275 {
276 assert (tc_parent->is_focused);
277 tc_parent = tc_parent->parent;
278 if (tc_parent->type == TERM_CONTAINER_TYPE_TABS)
279 {
280 Tabs *tabs = (Tabs*) tc_parent;
281 if (tabs->selector_bg)
282 return;
283 }
284 }
285 while (tc_parent->type != TERM_CONTAINER_TYPE_WIN);
286 assert (tc_parent->is_focused);
287 term_focused = tc_parent->focused_term_get(tc_parent);
288 assert(term_focused == term);
289 }
290 }
291 }
292 }
293 }
294 #else
295 static void
_focus_validator(void)296 _focus_validator(void)
297 {}
298 #endif
299
300 #define GROUPED_INPUT_TERM_FOREACH(_wn, _list, _term) \
301 EINA_LIST_FOREACH(_wn->terms, _list, _term) \
302 if (!_wn->group_only_visible || term_is_visible(_term))
303
304 /* }}} */
305 /* {{{ Scale */
306 static void
_scale_round(void * data EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)307 _scale_round(void *data EINA_UNUSED,
308 Evas_Object *obj,
309 void *event_info EINA_UNUSED)
310 {
311 double val = elm_slider_value_get(obj);
312 double v;
313
314 v = ((double)((int)(val * 10.0))) / 10.0;
315 if (v != val) elm_slider_value_set(obj, v);
316 }
317
318 static void
_scale_change(void * data EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)319 _scale_change(void *data EINA_UNUSED,
320 Evas_Object *obj,
321 void *event_info EINA_UNUSED)
322 {
323 double scale = elm_config_scale_get();
324 double val = elm_slider_value_get(obj);
325
326 if (scale == val)
327 return;
328 elm_config_scale_set(val);
329 elm_config_all_flush();
330 }
331
332 typedef struct _Scale_Ctx
333 {
334 Evas_Object *hv;
335 Term *term;
336 } Scale_Ctx;
337
338 static void
_scale_done(void * data,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)339 _scale_done(void *data,
340 Evas_Object *obj EINA_UNUSED,
341 void *event_info EINA_UNUSED)
342 {
343 Scale_Ctx *ctx = data;
344
345 evas_object_smart_callback_del_full(ctx->hv, "dismissed",
346 _scale_done, ctx);
347 evas_object_del(ctx->hv);
348 ctx->term->wn->on_popover--;
349 term_unref(ctx->term);
350 elm_config_save();
351 config_save(ctx->term->config);
352 free(ctx);
353 }
354
355 void
win_scale_wizard(Evas_Object * win,Term * term)356 win_scale_wizard(Evas_Object *win, Term *term)
357 {
358 Evas_Object *bx, *lbl, *sl, *fr, *bt;
359 const char *txt;
360 Scale_Ctx *ctx;
361
362 EINA_SAFETY_ON_NULL_RETURN(term);
363
364 ctx = calloc(1, sizeof(*ctx));
365 if (!ctx)
366 return;
367
368 ctx->term = term;
369
370 term->wn->on_popover++;
371
372 term_ref(term);
373
374 ctx->hv = elm_hover_add(win);
375 evas_object_size_hint_weight_set(ctx->hv, EVAS_HINT_EXPAND, 0.0);
376 evas_object_size_hint_align_set(ctx->hv, EVAS_HINT_FILL, 0.5);
377 elm_hover_parent_set(ctx->hv, win);
378 elm_hover_target_set(ctx->hv, win);
379 evas_object_smart_callback_add(ctx->hv, "dismissed", _scale_done, ctx);
380
381 fr = elm_frame_add(win);
382 evas_object_size_hint_weight_set(fr, EVAS_HINT_EXPAND, 0.0);
383 evas_object_size_hint_align_set(fr, EVAS_HINT_FILL, 0.5);
384 elm_object_text_set(fr, _("Scale"));
385 elm_object_part_content_set(ctx->hv, "middle", fr);
386 evas_object_show(fr);
387
388 bx = elm_box_add(win);
389 evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, 0.0);
390 evas_object_size_hint_align_set(bx, EVAS_HINT_FILL, 0.5);
391 elm_object_content_set(fr, bx);
392 evas_object_show(bx);
393
394 fr = elm_frame_add(win);
395 evas_object_size_hint_weight_set(fr, EVAS_HINT_EXPAND, 0.0);
396 evas_object_size_hint_align_set(fr, EVAS_HINT_FILL, 0.5);
397 elm_object_style_set(fr, "pad_medium");
398 elm_box_pack_end(bx, fr);
399 evas_object_show(fr);
400
401 lbl = elm_label_add(win);
402 evas_object_size_hint_weight_set(lbl, EVAS_HINT_EXPAND, 0.0);
403 evas_object_size_hint_align_set(lbl, EVAS_HINT_FILL, 0.5);
404 txt = eina_stringshare_printf("<hilight>%s</>",_("Scale"));
405 elm_object_text_set(lbl, txt);
406 eina_stringshare_del(txt);
407 elm_object_content_set(fr, lbl);
408 elm_box_pack_end(bx, lbl);
409 evas_object_show(lbl);
410
411 sl = elm_slider_add(win);
412 evas_object_size_hint_weight_set(sl, EVAS_HINT_EXPAND, 0.0);
413 evas_object_size_hint_align_set(sl, EVAS_HINT_FILL, 0.5);
414 elm_slider_span_size_set(sl, 120);
415 elm_slider_unit_format_set(sl, "%1.2f");
416 elm_slider_indicator_format_set(sl, "%1.2f");
417 elm_slider_min_max_set(sl, 0.25, 5.0);
418 elm_slider_value_set(sl, elm_config_scale_get());
419 elm_box_pack_end(bx, sl);
420 evas_object_show(sl);
421 evas_object_smart_callback_add(sl, "changed", _scale_round, NULL);
422 evas_object_smart_callback_add(sl, "delay,changed", _scale_change, NULL);
423
424 bt = elm_button_add(win);
425 elm_object_text_set(bt, _("Done"));
426 elm_box_pack_end(bx, bt);
427 evas_object_smart_callback_add(bt, "clicked", _scale_done, ctx);
428 evas_object_show(bt);
429
430 lbl = elm_label_add(win);
431 evas_object_size_hint_weight_set(lbl, EVAS_HINT_EXPAND, 0.0);
432 evas_object_size_hint_align_set(lbl, EVAS_HINT_FILL, 0.5);
433 elm_object_text_set(lbl, _("Select preferred size so that this text is readable"));
434 elm_label_line_wrap_set(lbl, ELM_WRAP_WORD);
435 elm_box_pack_end(bx, lbl);
436 evas_object_show(lbl);
437
438 lbl = elm_label_add(win);
439 evas_object_size_hint_weight_set(lbl, EVAS_HINT_EXPAND, 0.0);
440 evas_object_size_hint_align_set(lbl, EVAS_HINT_FILL, 0.5);
441 elm_object_text_set(lbl, _("The scale configuration can be changed in the Settings (right click on the terminal) → Toolkit, or by starting the command <keyword>elementary_config</keyword>"));
442 elm_label_line_wrap_set(lbl, ELM_WRAP_WORD);
443 elm_box_pack_end(bx, lbl);
444 evas_object_show(lbl);
445
446 evas_object_show(ctx->hv);
447
448 elm_object_focus_set(ctx->hv, EINA_TRUE);
449 elm_object_focus_set(bt, EINA_TRUE);
450 }
451
452 /* }}} */
453 /* {{{ Solo */
454
455 static Evas_Object *
_solo_get_evas_object(const Term_Container * tc)456 _solo_get_evas_object(const Term_Container *tc)
457 {
458 Solo *solo;
459 assert (tc->type == TERM_CONTAINER_TYPE_SOLO);
460 solo = (Solo*) tc;
461
462 return solo->term->bg;
463 }
464
465 static Term *
_solo_focused_term_get(const Term_Container * tc)466 _solo_focused_term_get(const Term_Container *tc)
467 {
468 Solo *solo;
469 Term *term = NULL;
470
471 assert (tc->type == TERM_CONTAINER_TYPE_SOLO);
472 solo = (Solo*)tc;
473
474 if (tc->is_focused)
475 term = solo->term;
476 return term;
477 }
478
479 static Term *
_solo_find_term_at_coords(const Term_Container * tc,Evas_Coord _mx EINA_UNUSED,Evas_Coord _my EINA_UNUSED)480 _solo_find_term_at_coords(const Term_Container *tc,
481 Evas_Coord _mx EINA_UNUSED,
482 Evas_Coord _my EINA_UNUSED)
483 {
484 Solo *solo;
485 assert (tc->type == TERM_CONTAINER_TYPE_SOLO);
486 solo = (Solo*) tc;
487
488 return solo->term;
489 }
490
491 static void
_solo_size_eval(Term_Container * container,Sizeinfo * info)492 _solo_size_eval(Term_Container *container, Sizeinfo *info)
493 {
494 Term *term;
495 int mw = 0, mh = 0;
496 Solo *solo;
497 assert (container->type == TERM_CONTAINER_TYPE_SOLO);
498 solo = (Solo*)container;
499
500 term = solo->term;
501
502 info->min_w = term->min_w;
503 info->min_h = term->min_h;
504 info->step_x = term->step_x;
505 info->step_y = term->step_y;
506 info->req_w = term->req_w;
507 info->req_h = term->req_h;
508 if (!evas_object_data_get(term->termio, "sizedone"))
509 {
510 evas_object_data_set(term->termio, "sizedone", term->termio);
511 info->req = 1;
512 }
513 evas_object_size_hint_min_get(term->bg, &mw, &mh);
514 info->bg_min_w = mw;
515 info->bg_min_h = mh;
516 }
517
518 static void
_solo_close(Term_Container * tc,Term_Container * _child EINA_UNUSED)519 _solo_close(Term_Container *tc,
520 Term_Container *_child EINA_UNUSED)
521 {
522 Solo *solo;
523 Term *term;
524
525 DBG("close");
526 assert (tc->type == TERM_CONTAINER_TYPE_SOLO);
527 solo = (Solo*) tc;
528 tc->parent->close(tc->parent, tc);
529
530 eina_stringshare_del(tc->title);
531
532 term = solo->term;
533 term->container = NULL;
534
535 free(tc);
536 }
537
538 static void
_solo_tabs_new(Term_Container * tc)539 _solo_tabs_new(Term_Container *tc)
540 {
541 if (tc->parent->type != TERM_CONTAINER_TYPE_TABS)
542 _tabs_new(tc, tc->parent);
543 _tab_new_cb(tc->parent, NULL, NULL);
544 }
545
546 static void
_solo_split(Term_Container * tc,Term_Container * _child EINA_UNUSED,Term * from,const char * cmd,Eina_Bool is_horizontal)547 _solo_split(Term_Container *tc,
548 Term_Container *_child EINA_UNUSED,
549 Term *from,
550 const char *cmd,
551 Eina_Bool is_horizontal)
552 {
553 tc->parent->split(tc->parent, tc, from, cmd, is_horizontal);
554 }
555
556 static int
_solo_split_direction(Term_Container * tc,Term_Container * child_orig EINA_UNUSED,Term_Container * child_new,Split_Direction direction)557 _solo_split_direction(Term_Container *tc,
558 Term_Container *child_orig EINA_UNUSED,
559 Term_Container *child_new,
560 Split_Direction direction)
561 {
562 return tc->parent->split_direction(tc->parent, tc, child_new, direction);
563 }
564
565 static Term *
_solo_term_next(const Term_Container * tc,const Term_Container * _child EINA_UNUSED)566 _solo_term_next(const Term_Container *tc,
567 const Term_Container *_child EINA_UNUSED)
568 {
569 return tc->parent->term_next(tc->parent, tc);
570 }
571
572 static Term *
_solo_term_prev(const Term_Container * tc,const Term_Container * _child EINA_UNUSED)573 _solo_term_prev(const Term_Container *tc,
574 const Term_Container *_child EINA_UNUSED)
575 {
576 return tc->parent->term_prev(tc->parent, tc);
577 }
578
579 static Term *
_solo_term_up(const Term_Container * tc,const Term_Container * _child EINA_UNUSED)580 _solo_term_up(const Term_Container *tc,
581 const Term_Container *_child EINA_UNUSED)
582 {
583 return tc->parent->term_up(tc->parent, tc);
584 }
585
586 static Term *
_solo_term_down(const Term_Container * tc,const Term_Container * _child EINA_UNUSED)587 _solo_term_down(const Term_Container *tc,
588 const Term_Container *_child EINA_UNUSED)
589 {
590 return tc->parent->term_down(tc->parent, tc);
591 }
592
593 static Term *
_solo_term_left(const Term_Container * tc,const Term_Container * _child EINA_UNUSED)594 _solo_term_left(const Term_Container *tc,
595 const Term_Container *_child EINA_UNUSED)
596 {
597 return tc->parent->term_left(tc->parent, tc);
598 }
599
600 static Term *
_solo_term_right(const Term_Container * tc,const Term_Container * _child EINA_UNUSED)601 _solo_term_right(const Term_Container *tc,
602 const Term_Container *_child EINA_UNUSED)
603 {
604 return tc->parent->term_right(tc->parent, tc);
605 }
606
607 static Term *
_solo_term_first(const Term_Container * tc)608 _solo_term_first(const Term_Container *tc)
609 {
610 Solo *solo;
611 assert (tc->type == TERM_CONTAINER_TYPE_SOLO);
612 solo = (Solo*) tc;
613 return solo->term;
614 }
615
616 static Term *
_solo_term_last(const Term_Container * tc)617 _solo_term_last(const Term_Container *tc)
618 {
619 Solo *solo;
620 assert (tc->type == TERM_CONTAINER_TYPE_SOLO);
621 solo = (Solo*) tc;
622 return solo->term;
623 }
624
625 static void
_solo_set_title(Term_Container * tc,Term_Container * _child EINA_UNUSED,const char * title)626 _solo_set_title(Term_Container *tc,
627 Term_Container *_child EINA_UNUSED,
628 const char *title)
629 {
630 Solo *solo;
631 Term *term;
632
633 assert (tc->type == TERM_CONTAINER_TYPE_SOLO);
634 solo = (Solo*) tc;
635 term = solo->term;
636
637 eina_stringshare_del(tc->title);
638 tc->title = eina_stringshare_add(title);
639 if (term->config->show_tabs)
640 {
641 elm_layout_text_set(term->bg, "terminology.tab.title", title);
642 }
643 if (_tab_drag && _tab_drag->term == term && _tab_drag->icon)
644 {
645 elm_layout_text_set(_tab_drag->icon,
646 "terminology.title", title);
647 }
648 tc->parent->set_title(tc->parent, tc, title);
649 }
650
651 static void
_solo_bell(Term_Container * tc,Term_Container * _child EINA_UNUSED)652 _solo_bell(Term_Container *tc,
653 Term_Container *_child EINA_UNUSED)
654 {
655 Solo *solo;
656 Term *term;
657
658 assert (tc->type == TERM_CONTAINER_TYPE_SOLO);
659 solo = (Solo*) tc;
660 term = solo->term;
661
662 if (!tc->is_focused)
663 term->missed_bell = EINA_TRUE;
664
665 if (!tc->wn->config->disable_visual_bell)
666 {
667 elm_layout_signal_emit(term->bg, "bell", "terminology");
668 elm_layout_signal_emit(term->core, "bell", "terminology");
669 if (tc->wn->config->bell_rings)
670 {
671 elm_layout_signal_emit(term->bg, "bell,ring", "terminology");
672 elm_layout_signal_emit(term->core, "bell,ring", "terminology");
673 }
674 if ((_tab_drag != NULL) && (_tab_drag->term == term))
675 {
676 elm_layout_signal_emit(_tab_drag->icon, "bell", "terminology");
677 }
678 }
679 if ((term->missed_bell) && (term->config->show_tabs)
680 && (tc->parent->type == TERM_CONTAINER_TYPE_SPLIT))
681 {
682 elm_layout_signal_emit(term->bg, "tab,bell,on", "terminology");
683 }
684 edje_object_message_signal_process(term->bg_edj);
685 tc->parent->bell(tc->parent, tc);
686 }
687
688 static void
_solo_unfocus(Term_Container * tc,Term_Container * relative)689 _solo_unfocus(Term_Container *tc, Term_Container *relative)
690 {
691 Solo *solo;
692 Term *term;
693
694 assert (tc->type == TERM_CONTAINER_TYPE_SOLO);
695 solo = (Solo*) tc;
696 term = solo->term;
697
698 DBG("tc:%p tc->is_focused:%d from_parent:%d term:%p",
699 tc, tc->is_focused, tc->parent == relative, term);
700 if (!tc->is_focused)
701 return;
702
703 tc->is_focused = EINA_FALSE;
704 termio_focus_out(term->termio);
705
706 if (tc->parent != relative)
707 tc->parent->unfocus(tc->parent, tc);
708
709 if (!term->config->disable_focus_visuals)
710 {
711 elm_layout_signal_emit(term->bg, "focus,out", "terminology");
712 elm_layout_signal_emit(term->core, "focus,out", "terminology");
713 }
714 }
715
716 static void
_solo_focus(Term_Container * tc,Term_Container * relative)717 _solo_focus(Term_Container *tc, Term_Container *relative)
718 {
719 Solo *solo;
720 Term *term;
721 const char *title;
722
723 assert (tc->type == TERM_CONTAINER_TYPE_SOLO);
724 solo = (Solo*) tc;
725 term = solo->term;
726
727 if (!tc->parent)
728 return;
729
730 DBG("tc:%p tc->is_focused:%d from_parent:%d term:%p",
731 tc, tc->is_focused, tc->parent == relative, term);
732 if (tc->is_focused)
733 return;
734
735 term->missed_bell = EINA_FALSE;
736 if ((term->config->show_tabs)
737 && (tc->parent->type == TERM_CONTAINER_TYPE_SPLIT))
738 {
739 elm_layout_signal_emit(term->bg, "tab,bell,off", "terminology");
740 }
741
742 if (term->config->disable_focus_visuals)
743 {
744 elm_layout_signal_emit(term->bg, "focused,set", "terminology");
745 elm_layout_signal_emit(term->core, "focused,set", "terminology");
746 }
747 else
748 {
749 elm_layout_signal_emit(term->bg, "focus,in", "terminology");
750 elm_layout_signal_emit(term->core, "focus,in", "terminology");
751 }
752 termio_event_feed_mouse_in(term->termio);
753 termio_focus_in(term->termio);
754
755 title = termio_title_get(term->termio);
756 if (title)
757 tc->set_title(tc, tc, title);
758
759 if (term->missed_bell)
760 term->missed_bell = EINA_FALSE;
761 edje_object_message_signal_process(term->bg_edj);
762 if (!tc->is_focused && relative != tc->parent)
763 {
764 tc->is_focused = EINA_TRUE;
765 tc->parent->focus(tc->parent, tc);
766 }
767 tc->is_focused = EINA_TRUE;
768 _focus_validator();
769 }
770
771 static Eina_Bool
_solo_is_visible(const Term_Container * tc,const Term_Container * _child EINA_UNUSED)772 _solo_is_visible(const Term_Container *tc, const Term_Container *_child EINA_UNUSED)
773 {
774 assert (tc->type == TERM_CONTAINER_TYPE_SOLO);
775 return tc->parent->is_visible(tc->parent, tc);
776 }
777
778 static void
_solo_tab_show(Term_Container * tc)779 _solo_tab_show(Term_Container *tc)
780 {
781 Solo *solo;
782 Term *term;
783
784 assert (tc->type == TERM_CONTAINER_TYPE_SOLO);
785 solo = (Solo*) tc;
786 term = solo->term;
787 DBG("tab show tc:%p", tc);
788
789 if (!term->tab_spacer)
790 {
791 Evas_Coord w = 0, h = 0;
792
793 term->tab_spacer = evas_object_rectangle_add(
794 evas_object_evas_get(term->bg));
795 evas_object_color_set(term->tab_spacer, 0, 0, 0, 0);
796 elm_coords_finger_size_adjust(1, &w, 1, &h);
797 evas_object_size_hint_min_set(term->tab_spacer, w, h);
798 elm_layout_content_set(term->bg, "terminology.tab", term->tab_spacer);
799 edje_object_part_drag_value_set(term->bg_edj,
800 "terminology.tabl", 0.0, 0.0);
801 edje_object_part_drag_value_set(term->bg_edj,
802 "terminology.tabr", 1.0, 0.0);
803 elm_layout_text_set(term->bg, "terminology.tab.title",
804 solo->tc.title);
805 elm_layout_signal_emit(term->bg, "tabbar,on", "terminology");
806 edje_object_message_signal_process(term->bg_edj);
807 }
808 else
809 {
810 edje_object_part_drag_value_set(term->bg_edj, "terminology.tabl", 0.0, 0.0);
811 edje_object_part_drag_value_set(term->bg_edj, "terminology.tabr", 1.0, 0.0);
812 edje_object_message_signal_process(term->bg_edj);
813 }
814 }
815
816 static void
_solo_tab_hide(Term_Container * tc)817 _solo_tab_hide(Term_Container *tc)
818 {
819 Solo *solo;
820 Term *term;
821
822 DBG("title hide tc:%p", tc);
823 assert (tc->type == TERM_CONTAINER_TYPE_SOLO);
824 solo = (Solo*) tc;
825 term = solo->term;
826
827 if (term->tab_spacer)
828 {
829 elm_layout_signal_emit(term->bg, "tabbar,off", "terminology");
830 edje_object_message_signal_process(term->bg_edj);
831 elm_layout_content_unset(term->bg, "terminology.tab");
832 evas_object_del(term->tab_spacer);
833 term->tab_spacer = NULL;
834 }
835 }
836
837 static void
_solo_update(Term_Container * tc)838 _solo_update(Term_Container *tc)
839 {
840 Solo *solo;
841 Term *term;
842 Term_Container *tc_parent = tc->parent;
843
844 assert (tc->type == TERM_CONTAINER_TYPE_SOLO);
845 solo = (Solo*) tc;
846 term = solo->term;
847
848 if (tc_parent->type == TERM_CONTAINER_TYPE_SPLIT)
849 {
850 if (term->config->show_tabs)
851 _solo_tab_show(tc);
852 else
853 _solo_tab_hide(tc);
854 }
855 }
856
857 static Term_Container *
_solo_new(Term * term,Win * wn)858 _solo_new(Term *term, Win *wn)
859 {
860 Term_Container *tc = NULL;
861 Solo *solo = NULL;
862 solo = calloc(1, sizeof(Solo));
863 if (!solo)
864 {
865 free(solo);
866 return NULL;
867 }
868
869 tc = (Term_Container*)solo;
870 tc->term_next = _solo_term_next;
871 tc->term_prev = _solo_term_prev;
872 tc->term_up = _solo_term_up;
873 tc->term_down = _solo_term_down;
874 tc->term_left = _solo_term_left;
875 tc->term_right = _solo_term_right;
876 tc->term_first = _solo_term_first;
877 tc->term_last = _solo_term_last;
878 tc->focused_term_get = _solo_focused_term_get;
879 tc->get_evas_object = _solo_get_evas_object;
880 tc->split = _solo_split;
881 tc->split_direction = _solo_split_direction;
882 tc->find_term_at_coords = _solo_find_term_at_coords;
883 tc->size_eval = _solo_size_eval;
884 tc->swallow = NULL;
885 tc->focus = _solo_focus;
886 tc->unfocus = _solo_unfocus;
887 tc->set_title = _solo_set_title;
888 tc->bell = _solo_bell;
889 tc->close = _solo_close;
890 tc->update = _solo_update;
891 tc->title = eina_stringshare_add("Terminology");
892 tc->is_visible = _solo_is_visible;
893 tc->detach = NULL;
894 tc->type = TERM_CONTAINER_TYPE_SOLO;
895
896 tc->parent = NULL;
897 tc->wn = wn;
898
899 solo->term = term;
900
901 term->container = tc;
902
903 return tc;
904 }
905
906 /* }}} */
907 /* {{{ Win */
908
909 static void
_cb_win_focus_in(void * data,Evas_Object * _obj EINA_UNUSED,void * _event EINA_UNUSED)910 _cb_win_focus_in(void *data,
911 Evas_Object *_obj EINA_UNUSED,
912 void *_event EINA_UNUSED)
913 {
914 Win *wn = data;
915 Term_Container *tc = (Term_Container*) wn;
916 Term *term;
917
918 DBG("FOCUS_IN tc:%p tc->is_focused:%d",
919 tc, tc->is_focused);
920 if (!tc->is_focused)
921 elm_win_urgent_set(wn->win, EINA_FALSE);
922 tc->is_focused = EINA_TRUE;
923 if (wn->on_popover)
924 return;
925
926 term = tc->focused_term_get(tc);
927
928 if (wn->group_input)
929 {
930 Eina_List *l;
931 Term *t;
932
933 GROUPED_INPUT_TERM_FOREACH(wn, l, t)
934 {
935 elm_layout_signal_emit(t->bg, "focus,in", "terminology");
936 termio_event_feed_mouse_in(t->termio);
937 termio_focus_in(t->termio);
938 }
939 }
940 else if ( wn->config->mouse_over_focus )
941 {
942 Term *term_mouse;
943 Evas_Coord mx, my;
944
945 evas_pointer_canvas_xy_get(evas_object_evas_get(wn->win), &mx, &my);
946 term_mouse = tc->find_term_at_coords(tc, mx, my);
947 if ((term_mouse) && (term_mouse != term))
948 {
949 if (term)
950 {
951 if (!term->config->disable_focus_visuals)
952 {
953 elm_layout_signal_emit(term->bg, "focus,out", "terminology");
954 elm_layout_signal_emit(term->core, "focus,out", "terminology");
955 }
956 }
957 term = term_mouse;
958 }
959 }
960
961 if (term)
962 {
963 term_focus(term);
964 }
965 else
966 {
967 DBG("focus tc:%p", tc);
968 tc->focus(tc, tc);
969 }
970 }
971
972 static void
_cb_win_focus_out(void * data,Evas_Object * _obj EINA_UNUSED,void * _event EINA_UNUSED)973 _cb_win_focus_out(void *data,
974 Evas_Object *_obj EINA_UNUSED,
975 void *_event EINA_UNUSED)
976 {
977 Win *wn = data;
978 Term_Container *tc = (Term_Container*) wn;
979
980 if (wn->on_popover)
981 return;
982
983 DBG("FOCUS OUT tc:%p tc->is_focused:%d",
984 tc, tc->is_focused);
985 tc->unfocus(tc, NULL);
986 if (wn->group_input)
987 {
988 Eina_List *l;
989 Term *term;
990
991 GROUPED_INPUT_TERM_FOREACH(wn, l, term)
992 {
993 elm_layout_signal_emit(term->bg, "focus,out", "terminology");
994 termio_focus_out(term->termio);
995 }
996 }
997 }
998
999 static Eina_Bool
_win_is_focused(Win * wn)1000 _win_is_focused(Win *wn)
1001 {
1002 Term_Container *tc;
1003
1004 if (!wn)
1005 return EINA_FALSE;
1006 tc = (Term_Container*) wn;
1007
1008 DBG("tc:%p tc->is_focused:%d",
1009 tc, tc->is_focused);
1010 return tc->is_focused;
1011 }
1012
1013
win_term_set(Win * wn,Term * term)1014 int win_term_set(Win *wn, Term *term)
1015 {
1016 Term_Container *tc_win = NULL, *tc_child = NULL;
1017
1018 tc_child = _solo_new(term, wn);
1019 if (!tc_child)
1020 goto bad;
1021
1022 tc_win = (Term_Container*) wn;
1023
1024 tc_win->swallow(tc_win, NULL, tc_child);
1025
1026 _cb_size_hint(term, NULL, term->termio, NULL);
1027
1028 return 0;
1029
1030 bad:
1031 free(tc_child);
1032 return -1;
1033 }
1034
1035
1036 Config *
win_config_get(const Win * wn)1037 win_config_get(const Win *wn)
1038 {
1039 return wn->config;
1040 }
1041
1042 Eina_List *
win_terms_get(const Win * wn)1043 win_terms_get(const Win *wn)
1044 {
1045 return wn->terms;
1046 }
1047
1048 Evas_Object *
win_evas_object_get(const Win * wn)1049 win_evas_object_get(const Win *wn)
1050 {
1051 return wn->win;
1052 }
1053
1054 static void
_term_trans(Term * term)1055 _term_trans(Term *term)
1056 {
1057 Edje_Message_Int msg;
1058 Evas_Object *edje = elm_layout_edje_get(term->core);
1059 Win *wn = term->wn;
1060
1061 if (term->config->translucent)
1062 msg.val = term->config->opacity;
1063 else
1064 msg.val = 100;
1065 edje_object_message_send(term->bg_edj, EDJE_MESSAGE_INT, 1, &msg);
1066 edje_object_message_send(edje, EDJE_MESSAGE_INT, 1, &msg);
1067
1068 if (term->config->translucent != wn->translucent)
1069 {
1070 if (term->config->translucent)
1071 {
1072 elm_win_alpha_set(wn->win, EINA_TRUE);
1073 evas_object_hide(wn->backbg);
1074 wn->translucent = EINA_TRUE;
1075 }
1076 else
1077 {
1078 elm_win_alpha_set(wn->win, EINA_FALSE);
1079 evas_object_show(wn->backbg);
1080 wn->translucent = EINA_FALSE;
1081 }
1082 }
1083 }
1084
1085 void
main_trans_update(void)1086 main_trans_update(void)
1087 {
1088 Win *wn;
1089 Term *term;
1090 Eina_List *l, *ll;
1091
1092 EINA_LIST_FOREACH(wins, l, wn)
1093 {
1094 EINA_LIST_FOREACH(wn->terms, ll, term)
1095 {
1096 _term_trans(term);
1097 }
1098 }
1099 }
1100
1101
1102 static void
_cb_del(void * data,Evas * _e EINA_UNUSED,Evas_Object * _obj EINA_UNUSED,void * _event EINA_UNUSED)1103 _cb_del(void *data,
1104 Evas *_e EINA_UNUSED,
1105 Evas_Object *_obj EINA_UNUSED,
1106 void *_event EINA_UNUSED)
1107 {
1108 Win *wn = data;
1109
1110 // already obj here is deleted - dont do it again
1111 wn->win = NULL;
1112 win_free(wn);
1113 }
1114
1115 void
win_free(Win * wn)1116 win_free(Win *wn)
1117 {
1118 Term *term;
1119
1120 wins = eina_list_remove(wins, wn);
1121 if (wn->config_elm_handler)
1122 {
1123 ecore_event_handler_del(wn->config_elm_handler);
1124 wn->config_elm_handler = NULL;
1125 }
1126 EINA_LIST_FREE(wn->terms, term)
1127 {
1128 term_unref(term);
1129 }
1130 if (wn->cmdbox_del_timer)
1131 {
1132 ecore_timer_del(wn->cmdbox_del_timer);
1133 wn->cmdbox_del_timer = NULL;
1134 }
1135 if (wn->cmdbox)
1136 {
1137 evas_object_del(wn->cmdbox);
1138 wn->cmdbox = NULL;
1139 }
1140 if (wn->win)
1141 {
1142 evas_object_smart_callback_del_full(wn->win, "focus,in", _cb_win_focus_in, wn);
1143 evas_object_smart_callback_del_full(wn->win, "focus,out", _cb_win_focus_out, wn);
1144 evas_object_event_callback_del_full(wn->win, EVAS_CALLBACK_DEL, _cb_del, wn);
1145 evas_object_del(wn->win);
1146 }
1147 if (wn->size_job)
1148 ecore_job_del(wn->size_job);
1149 config_del(wn->config);
1150 eina_stringshare_del(wn->preedit_str);
1151 keyin_compose_seq_reset(&wn->khdl);
1152 if (wn->khdl.imf)
1153 {
1154 ecore_imf_context_event_callback_del
1155 (wn->khdl.imf, ECORE_IMF_CALLBACK_COMMIT, _imf_event_commit_cb);
1156 ecore_imf_context_del(wn->khdl.imf);
1157 }
1158 if (wn->hide_cursor_timer)
1159 {
1160 ecore_timer_del(wn->hide_cursor_timer);
1161 }
1162 ecore_imf_shutdown();
1163 free(wn);
1164 }
1165
1166 Win *
win_evas_object_to_win(const Evas_Object * win)1167 win_evas_object_to_win(const Evas_Object *win)
1168 {
1169 Win *wn;
1170 Eina_List *l;
1171
1172 EINA_LIST_FOREACH(wins, l, wn)
1173 {
1174 if (wn->win == win) return wn;
1175 }
1176 return NULL;
1177 }
1178
1179 Eina_List *
terms_from_win_object(Evas_Object * win)1180 terms_from_win_object(Evas_Object *win)
1181 {
1182 Win *wn;
1183
1184 wn = win_evas_object_to_win(win);
1185 if (!wn) return NULL;
1186
1187 return wn->terms;
1188 }
1189
1190
1191 static Evas_Object *
win_add(const char * name,const char * role,const char * title,const char * icon_name)1192 win_add(const char *name, const char *role,
1193 const char *title, const char *icon_name)
1194 {
1195 Evas_Object *win;
1196
1197 if (!name) name = "main";
1198 if (!title) title = "Terminology";
1199 if (!icon_name) icon_name = "terminology";
1200
1201 win = elm_win_add(NULL, name, ELM_WIN_BASIC);
1202 elm_win_title_set(win, title);
1203 elm_win_icon_name_set(win, icon_name);
1204 if (role) elm_win_role_set(win, role);
1205
1206 elm_win_autodel_set(win, EINA_TRUE);
1207
1208 return win;
1209 }
1210
1211 static Evas_Object *
_win_get_evas_object(const Term_Container * tc)1212 _win_get_evas_object(const Term_Container *tc)
1213 {
1214 Win *wn;
1215 assert (tc->type == TERM_CONTAINER_TYPE_WIN);
1216
1217 wn = (Win*) tc;
1218
1219 return wn->win;
1220 }
1221
1222 static Term *
_win_term_next(const Term_Container * _tc EINA_UNUSED,const Term_Container * child)1223 _win_term_next(const Term_Container *_tc EINA_UNUSED,
1224 const Term_Container *child)
1225 {
1226 return child->term_first(child);
1227 }
1228
1229 static Term *
_win_term_prev(const Term_Container * _tc EINA_UNUSED,const Term_Container * child)1230 _win_term_prev(const Term_Container *_tc EINA_UNUSED,
1231 const Term_Container *child)
1232 {
1233 return child->term_last(child);
1234 }
1235
1236 static Term *
_win_term_up(const Term_Container * _tc EINA_UNUSED,const Term_Container * child EINA_UNUSED)1237 _win_term_up(const Term_Container *_tc EINA_UNUSED,
1238 const Term_Container *child EINA_UNUSED)
1239 {
1240 return NULL;
1241 }
1242
1243 static Term *
_win_term_down(const Term_Container * _tc EINA_UNUSED,const Term_Container * child EINA_UNUSED)1244 _win_term_down(const Term_Container *_tc EINA_UNUSED,
1245 const Term_Container *child EINA_UNUSED)
1246 {
1247 return NULL;
1248 }
1249
1250 static Term *
_win_term_left(const Term_Container * _tc EINA_UNUSED,const Term_Container * child EINA_UNUSED)1251 _win_term_left(const Term_Container *_tc EINA_UNUSED,
1252 const Term_Container *child EINA_UNUSED)
1253 {
1254 return NULL;
1255 }
1256
1257 static Term *
_win_term_right(const Term_Container * _tc EINA_UNUSED,const Term_Container * child EINA_UNUSED)1258 _win_term_right(const Term_Container *_tc EINA_UNUSED,
1259 const Term_Container *child EINA_UNUSED)
1260 {
1261 return NULL;
1262 }
1263
1264 static Term *
_win_term_first(const Term_Container * tc)1265 _win_term_first(const Term_Container *tc)
1266 {
1267 Win *wn;
1268 assert (tc->type == TERM_CONTAINER_TYPE_WIN);
1269
1270 wn = (Win*) tc;
1271 return wn->child->term_first(wn->child);
1272 }
1273
1274 static Term *
_win_term_last(const Term_Container * tc)1275 _win_term_last(const Term_Container *tc)
1276 {
1277 Win *wn;
1278 assert (tc->type == TERM_CONTAINER_TYPE_WIN);
1279
1280 wn = (Win*) tc;
1281 return wn->child->term_last(wn->child);
1282 }
1283
1284 static Term *
_win_focused_term_get(const Term_Container * tc)1285 _win_focused_term_get(const Term_Container *tc)
1286 {
1287 Win *wn;
1288 Term *term = NULL;
1289
1290 assert (tc->type == TERM_CONTAINER_TYPE_WIN);
1291
1292 wn = (Win*) tc;
1293 if (tc->is_focused && wn->child)
1294 term = wn->child->focused_term_get(wn->child);
1295 return term;
1296 }
1297
1298 static Term *
_win_find_term_at_coords(const Term_Container * tc,Evas_Coord mx,Evas_Coord my)1299 _win_find_term_at_coords(const Term_Container *tc,
1300 Evas_Coord mx, Evas_Coord my)
1301 {
1302 Win *wn;
1303 assert (tc->type == TERM_CONTAINER_TYPE_WIN);
1304
1305 wn = (Win*) tc;
1306
1307 if (!wn->child)
1308 return NULL;
1309
1310 return wn->child->find_term_at_coords(wn->child, mx, my);
1311 }
1312
1313 static void
_win_size_eval(Term_Container * tc,Sizeinfo * info)1314 _win_size_eval(Term_Container *tc, Sizeinfo *info)
1315 {
1316 Win *wn;
1317 assert (tc->type == TERM_CONTAINER_TYPE_WIN);
1318
1319 wn = (Win*) tc;
1320
1321 assert(wn->child);
1322 wn->child->size_eval(wn->child, info);
1323 }
1324
1325 static void
_win_swallow(Term_Container * tc,Term_Container * orig,Term_Container * new_child)1326 _win_swallow(Term_Container *tc, Term_Container *orig,
1327 Term_Container *new_child)
1328 {
1329 Win *wn;
1330 Evas_Object *o;
1331
1332 assert (tc->type == TERM_CONTAINER_TYPE_WIN);
1333
1334 wn = (Win*) tc;
1335
1336 DBG("orig:%p", orig);
1337
1338 if (orig)
1339 {
1340 elm_layout_content_unset(wn->base, "terminology.content");
1341 }
1342
1343 o = new_child->get_evas_object(new_child);
1344 elm_layout_content_set(wn->base, "terminology.content", o);
1345
1346 if ((new_child->type == TERM_CONTAINER_TYPE_SOLO)
1347 && (wn->config->show_tabs))
1348 {
1349 if (_tab_drag && _tab_drag->term && (_tab_drag->term->wn == wn) &&
1350 _tab_drag->icon)
1351 _solo_tab_show(new_child);
1352 else
1353 _solo_tab_hide(new_child);
1354 }
1355
1356 evas_object_show(o);
1357 new_child->parent = tc;
1358 wn->child = new_child;
1359
1360 if (_tab_drag && _tab_drag->icon)
1361 {
1362 evas_object_raise(_tab_drag->icon);
1363 }
1364 }
1365
1366 static void
_win_close(Term_Container * tc,Term_Container * _child EINA_UNUSED)1367 _win_close(Term_Container *tc,
1368 Term_Container *_child EINA_UNUSED)
1369 {
1370 Win *wn;
1371 assert (tc->type == TERM_CONTAINER_TYPE_WIN);
1372 wn = (Win*) tc;
1373
1374 DBG("win close");
1375 if (_tab_drag && _tab_drag->term && (_tab_drag->term->wn == wn))
1376 {
1377 _tab_drag->parent_type = TERM_CONTAINER_TYPE_WIN;
1378 _tab_drag_free();
1379 return;
1380 }
1381 eina_stringshare_del(tc->title);
1382 win_free(wn);
1383 }
1384
1385 static void
_win_focus(Term_Container * tc,Term_Container * relative)1386 _win_focus(Term_Container *tc, Term_Container *relative)
1387 {
1388 Win *wn;
1389 assert (tc->type == TERM_CONTAINER_TYPE_WIN);
1390
1391 wn = (Win*) tc;
1392 elm_object_focus_allow_set(wn->base, EINA_TRUE);
1393 DBG("tc:%p tc->is_focused:%d from_child:%d",
1394 tc, tc->is_focused, wn->child == relative);
1395 elm_object_focus_set(wn->base, EINA_TRUE);
1396
1397 if (!tc->is_focused)
1398 elm_win_urgent_set(wn->win, EINA_FALSE);
1399
1400 tc->is_focused = EINA_TRUE;
1401 if ((relative != wn->child) || (!wn->focused))
1402 {
1403 DBG("focus tc:%p", tc);
1404 wn->child->focus(wn->child, tc);
1405 elm_win_keyboard_mode_set(wn->win, ELM_WIN_KEYBOARD_TERMINAL);
1406 if (wn->khdl.imf)
1407 {
1408 Term *focused;
1409
1410 ecore_imf_context_input_panel_show(wn->khdl.imf);
1411 ecore_imf_context_reset(wn->khdl.imf);
1412 ecore_imf_context_focus_in(wn->khdl.imf);
1413
1414 focused = tc->focused_term_get(tc);
1415 if (focused)
1416 termio_imf_cursor_set(focused->termio, wn->khdl.imf);
1417 }
1418 }
1419 }
1420
1421 static void
_win_unfocus(Term_Container * tc,Term_Container * relative)1422 _win_unfocus(Term_Container *tc, Term_Container *relative)
1423 {
1424 Win *wn;
1425 assert (tc->type == TERM_CONTAINER_TYPE_WIN);
1426
1427 wn = (Win*) tc;
1428
1429 elm_object_focus_set(wn->base, EINA_FALSE);
1430 elm_object_focus_allow_set(wn->base, EINA_FALSE);
1431
1432 DBG("tc:%p tc->is_focused:%d from_child:%d",
1433 tc, tc->is_focused, wn->child == relative);
1434 elm_win_keyboard_mode_set(wn->win, ELM_WIN_KEYBOARD_OFF);
1435 if (relative != wn->child && wn->child)
1436 {
1437 if (wn->khdl.imf)
1438 {
1439 Term *focused;
1440
1441 ecore_imf_context_reset(wn->khdl.imf);
1442 focused = tc->focused_term_get(tc);
1443 if (focused)
1444 termio_imf_cursor_set(focused->termio, wn->khdl.imf);
1445 ecore_imf_context_focus_out(wn->khdl.imf);
1446 ecore_imf_context_input_panel_hide(wn->khdl.imf);
1447 }
1448 tc->is_focused = EINA_FALSE;
1449 wn->child->unfocus(wn->child, tc);
1450 }
1451 }
1452
1453 static void
_win_bell(Term_Container * tc,Term_Container * _child EINA_UNUSED)1454 _win_bell(Term_Container *tc,
1455 Term_Container *_child EINA_UNUSED)
1456 {
1457 Win *wn;
1458 assert (tc->type == TERM_CONTAINER_TYPE_WIN);
1459
1460 wn = (Win*) tc;
1461
1462 if (tc->is_focused) return;
1463
1464 if (wn->config->urg_bell)
1465 {
1466 elm_win_urgent_set(wn->win, EINA_TRUE);
1467 }
1468 }
1469
1470 static void
_win_set_title(Term_Container * tc,Term_Container * _child EINA_UNUSED,const char * title)1471 _win_set_title(Term_Container *tc,
1472 Term_Container *_child EINA_UNUSED,
1473 const char *title)
1474 {
1475 Win *wn;
1476 assert (tc->type == TERM_CONTAINER_TYPE_WIN);
1477
1478 wn = (Win*) tc;
1479
1480 eina_stringshare_del(tc->title);
1481 tc->title = eina_stringshare_ref(title);
1482
1483 elm_win_title_set(wn->win, title);
1484 }
1485
1486 Eina_Bool
_term_container_is_splittable(Term_Container * tc,Eina_Bool is_horizontal)1487 _term_container_is_splittable(Term_Container *tc, Eina_Bool is_horizontal)
1488 {
1489 int w = 0, h = 0, c_w = 0, c_h = 0;
1490 Term *tm;
1491
1492 if (terminology_starting_up)
1493 return EINA_TRUE;
1494
1495 tm = tc->term_first(tc);
1496 evas_object_geometry_get(tm->bg, NULL, NULL, &w, &h);
1497 evas_object_textgrid_cell_size_get(termio_textgrid_get(tm->termio),
1498 &c_w, &c_h);
1499 if (is_horizontal)
1500 {
1501 if (c_h * 2 > h)
1502 return EINA_FALSE;
1503 }
1504 else
1505 {
1506 if (c_w * 2 > w)
1507 return EINA_FALSE;
1508 }
1509 return EINA_TRUE;
1510 }
1511
1512 static void
_win_split(Term_Container * tc,Term_Container * child,Term * from,const char * cmd,Eina_Bool is_horizontal)1513 _win_split(Term_Container *tc, Term_Container *child,
1514 Term *from, const char *cmd, Eina_Bool is_horizontal)
1515 {
1516 Win *wn;
1517
1518 assert (tc->type == TERM_CONTAINER_TYPE_WIN);
1519 wn = (Win*) tc;
1520
1521 if (_term_container_is_splittable(tc, is_horizontal))
1522 {
1523 Term *tm_new, *tm;
1524 Term_Container *tc_split, *tc_solo_new;
1525 char *wdir = NULL;
1526 char buf[PATH_MAX];
1527
1528 // copy the current path to wdir if we should change the directory,
1529 // passing wdir NULL otherwise:
1530 if (wn->config->changedir_to_current)
1531 {
1532 if (from)
1533 tm = from;
1534 else
1535 tm = tc->focused_term_get(tc);
1536 if (tm && termio_cwd_get(tm->termio, buf, sizeof(buf)))
1537 wdir = buf;
1538 }
1539 tm_new = term_new(wn, wn->config,
1540 cmd, wn->config->login_shell, wdir,
1541 80, 24, EINA_FALSE, NULL);
1542 tc_solo_new = _solo_new(tm_new, wn);
1543 evas_object_data_set(tm_new->termio, "sizedone", tm_new->termio);
1544
1545 elm_layout_content_unset(wn->base, "terminology.content");
1546
1547 tc_split = _split_new(child, tc_solo_new, 0.5, is_horizontal);
1548 if (wn->config->show_tabs)
1549 {
1550 if (child->type == TERM_CONTAINER_TYPE_SOLO)
1551 {
1552 _solo_tab_show(child);
1553 }
1554 _solo_tab_show(tc_solo_new);
1555 }
1556
1557 child->unfocus(child, tc_split);
1558 tc->swallow(tc, NULL, tc_split);
1559 tc_split->is_focused = EINA_TRUE;
1560 tc_split->focus(tc_split, tc_solo_new);
1561 tc_solo_new->focus(tc_solo_new, tc_split);
1562 }
1563 else
1564 {
1565 ERR("term is not splittable");
1566 }
1567 }
1568
1569 static int
_win_split_direction(Term_Container * tc,Term_Container * child_orig,Term_Container * child_new,Split_Direction direction)1570 _win_split_direction(Term_Container *tc,
1571 Term_Container *child_orig,
1572 Term_Container *child_new,
1573 Split_Direction direction)
1574 {
1575 Term_Container *child1, *child2, *tc_split;
1576 Win *wn;
1577 Eina_Bool is_horizontal =
1578 (direction == SPLIT_DIRECTION_LEFT) || (direction == SPLIT_DIRECTION_RIGHT) ?
1579 EINA_FALSE : EINA_TRUE;
1580
1581 assert (tc->type == TERM_CONTAINER_TYPE_WIN);
1582 wn = (Win*) tc;
1583
1584 if (!_term_container_is_splittable(tc, is_horizontal))
1585 {
1586 ERR("term is not splittable");
1587 return -1;
1588 }
1589
1590 if ((direction == SPLIT_DIRECTION_TOP) ||
1591 (direction == SPLIT_DIRECTION_LEFT))
1592 {
1593 child1 = child_new;
1594 child2 = child_orig;
1595 }
1596 else
1597 {
1598 child1 = child_orig;
1599 child2 = child_new;
1600 }
1601
1602 wn->tc.unfocus(&wn->tc, NULL); /* unfocus from top */
1603
1604 tc_split = _split_new(child1, child2, 0.5, is_horizontal);
1605
1606 if (wn->config->show_tabs)
1607 {
1608 if (child_orig->type == TERM_CONTAINER_TYPE_SOLO)
1609 {
1610 _solo_tab_show(child_orig);
1611 }
1612 _solo_tab_show(child_new);
1613 }
1614
1615 tc_split->is_focused = tc->is_focused;
1616 tc->swallow(tc, NULL, tc_split);
1617
1618 child_new->focus(child_new, NULL); /* refocus from bottom */
1619
1620 return 0;
1621 }
1622
1623 static Eina_Bool
_set_cursor(Term * term,void * data)1624 _set_cursor(Term *term, void *data)
1625 {
1626 const char *cursor = data;
1627
1628 assert(term->core);
1629 if (cursor)
1630 {
1631 elm_object_cursor_set(term->core, cursor);
1632 term->core_cursor_set = 1;
1633 }
1634 else
1635 {
1636 if (term->core_cursor_set)
1637 elm_object_cursor_unset(term->core);
1638 term->core_cursor_set = 0;
1639 }
1640
1641 return ECORE_CALLBACK_PASS_ON;
1642 }
1643
1644 static void
_win_update(Term_Container * tc)1645 _win_update(Term_Container *tc)
1646 {
1647 Win *wn;
1648
1649 assert (tc->type == TERM_CONTAINER_TYPE_WIN);
1650 wn = (Win*) tc;
1651
1652 if (wn->config->hide_cursor >= CONFIG_CURSOR_IDLE_TIMEOUT_MAX)
1653 {
1654 ecore_timer_del(wn->hide_cursor_timer);
1655 wn->hide_cursor_timer = NULL;
1656
1657 for_each_term_do(wn, &_set_cursor, NULL);
1658 }
1659
1660 wn->child->update(wn->child);
1661 }
1662
1663 Eina_Bool
win_has_single_child(const Win * wn)1664 win_has_single_child(const Win *wn)
1665 {
1666 const Term_Container *child = wn->child;
1667
1668 return (child->type == TERM_CONTAINER_TYPE_SOLO);
1669 }
1670
1671 static void
_cb_win_key_up(void * data,Evas * _e EINA_UNUSED,Evas_Object * _obj EINA_UNUSED,void * event)1672 _cb_win_key_up(void *data,
1673 Evas *_e EINA_UNUSED,
1674 Evas_Object *_obj EINA_UNUSED,
1675 void *event)
1676 {
1677 Win *wn = data;
1678 Evas_Event_Key_Up *ev = event;
1679
1680 DBG("GROUP key up (%p) (ctrl:%d)",
1681 wn, evas_key_modifier_is_set(ev->modifiers, "Control"));
1682 keyin_handle_up(&wn->khdl, ev);
1683 }
1684
1685 const char *
term_preedit_str_get(Term * term)1686 term_preedit_str_get(Term *term)
1687 {
1688 Win *wn = term->wn;
1689 Term_Container *tc = (Term_Container*) wn;
1690
1691 if (wn->on_popover)
1692 return NULL;
1693 tc = (Term_Container*) wn;
1694 term = tc->focused_term_get(tc);
1695 if (term)
1696 {
1697 return wn->preedit_str;
1698 }
1699 return NULL;
1700 }
1701
1702 Ecore_IMF_Context *
term_imf_context_get(Term * term)1703 term_imf_context_get(Term *term)
1704 {
1705 Win *wn = term->wn;
1706 Term_Container *tc = (Term_Container*) wn;
1707 Term *focused;
1708
1709 tc = (Term_Container*) wn;
1710 focused = tc->focused_term_get(tc);
1711 if (term == focused)
1712 return wn->khdl.imf;
1713 return NULL;
1714 }
1715
1716 static void
_imf_event_commit_cb(void * data,Ecore_IMF_Context * _ctx EINA_UNUSED,void * event)1717 _imf_event_commit_cb(void *data,
1718 Ecore_IMF_Context *_ctx EINA_UNUSED,
1719 void *event)
1720 {
1721 Eina_List *l;
1722 Term *term;
1723 Win *wn = data;
1724 Termpty *ty;
1725 char *str = event;
1726 int len;
1727 DBG("IMF committed '%s'", str);
1728 if (!str)
1729 return;
1730 len = strlen(str);
1731 if (wn->group_input)
1732 {
1733 GROUPED_INPUT_TERM_FOREACH(wn, l, term)
1734 {
1735 ty = termio_pty_get(term->termio);
1736 if (ty)
1737 termpty_write(ty, str, len);
1738 }
1739 }
1740 else
1741 {
1742 Term_Container *tc = (Term_Container*) wn;
1743
1744 term = tc->focused_term_get(tc);
1745 if (term)
1746 {
1747 ty = termio_pty_get(term->termio);
1748 if (ty)
1749 termpty_write(ty, str, len);
1750 }
1751 }
1752 eina_stringshare_del(wn->preedit_str);
1753 wn->preedit_str = NULL;
1754 }
1755
1756
1757
1758 static void
_imf_event_delete_surrounding_cb(void * data,Ecore_IMF_Context * _ctx EINA_UNUSED,void * event)1759 _imf_event_delete_surrounding_cb(void *data,
1760 Ecore_IMF_Context *_ctx EINA_UNUSED,
1761 void *event)
1762 {
1763 Win *wn = data;
1764 Ecore_IMF_Event_Delete_Surrounding *ev = event;
1765 DBG("IMF del surrounding %p %i %i", wn, ev->offset, ev->n_chars);
1766 }
1767
1768 static void
_imf_event_preedit_changed_cb(void * data,Ecore_IMF_Context * ctx,void * _event EINA_UNUSED)1769 _imf_event_preedit_changed_cb(void *data,
1770 Ecore_IMF_Context *ctx,
1771 void *_event EINA_UNUSED)
1772 {
1773 Win *wn = data;
1774 char *preedit_string;
1775 int cursor_pos;
1776
1777 ecore_imf_context_preedit_string_get(ctx, &preedit_string, &cursor_pos);
1778 if (!preedit_string)
1779 return;
1780 DBG("IMF preedit str '%s'", preedit_string);
1781 eina_stringshare_del(wn->preedit_str);
1782 wn->preedit_str = eina_stringshare_add(preedit_string);
1783 free(preedit_string);
1784 }
1785
1786
1787 static void
_cb_win_key_down(void * data,Evas * _e EINA_UNUSED,Evas_Object * _obj EINA_UNUSED,void * event_info)1788 _cb_win_key_down(void *data,
1789 Evas *_e EINA_UNUSED,
1790 Evas_Object *_obj EINA_UNUSED,
1791 void *event_info)
1792 {
1793 Win *wn = data;
1794 Eina_List *l = NULL;
1795 Term *term = NULL;
1796 Termpty *ty = NULL;
1797 Evas_Event_Key_Down *ev = event_info;
1798 Eina_Bool done = EINA_FALSE;
1799 int ctrl, alt, shift, win, meta, hyper;
1800
1801 DBG("GROUP key down (%p) (ctrl:%d)",
1802 wn, evas_key_modifier_is_set(ev->modifiers, "Control"));
1803 _focus_validator();
1804 if ((wn->on_popover) || (wn->cmdbox_up)) return;
1805
1806 ctrl = evas_key_modifier_is_set(ev->modifiers, "Control");
1807 alt = evas_key_modifier_is_set(ev->modifiers, "Alt");
1808 shift = evas_key_modifier_is_set(ev->modifiers, "Shift");
1809 win = evas_key_modifier_is_set(ev->modifiers, "Super");
1810 meta = evas_key_modifier_is_set(ev->modifiers, "Meta") ||
1811 evas_key_modifier_is_set(ev->modifiers, "AltGr") ||
1812 evas_key_modifier_is_set(ev->modifiers, "ISO_Level3_Shift");
1813 hyper = evas_key_modifier_is_set(ev->modifiers, "Hyper");
1814
1815 /* 1st/ Tab selector */
1816 {
1817 Term_Container *tc = (Term_Container*) wn;
1818
1819 term = tc->focused_term_get(tc);
1820 if (term)
1821 {
1822 Term_Container *tc_parent = tc->parent;
1823
1824 tc = term->container;
1825 tc_parent = tc->parent;
1826
1827 if (tc_parent->type == TERM_CONTAINER_TYPE_TABS)
1828 {
1829 Tabs *tabs = (Tabs*) tc_parent;
1830
1831 if (tabs->selector != NULL)
1832 {
1833 sel_key_down(tabs->selector, ev);
1834 return;
1835 }
1836 }
1837 }
1838 }
1839
1840 /* 2nd/ Miniview */
1841 if (wn->group_input)
1842 {
1843 GROUPED_INPUT_TERM_FOREACH(wn, l, term)
1844 {
1845 done = miniview_handle_key(term_miniview_get(term), ev);
1846 if (!wn->group_input)
1847 return;
1848 }
1849 }
1850 else
1851 {
1852 Term_Container *tc = (Term_Container*) wn;
1853
1854 term = tc->focused_term_get(tc);
1855 if (!term)
1856 {
1857 DBG("no focused term");
1858 return;
1859 }
1860 done = miniview_handle_key(term_miniview_get(term), ev);
1861 }
1862 if (done)
1863 {
1864 keyin_compose_seq_reset(&wn->khdl);
1865 goto end;
1866 }
1867
1868
1869 /* 3rd/ PopMedia */
1870 done = EINA_FALSE;
1871 if (wn->group_input)
1872 {
1873 GROUPED_INPUT_TERM_FOREACH(wn, l, term)
1874 {
1875 if (term_has_popmedia(term) && !strcmp(ev->key, "Escape"))
1876 {
1877 term_popmedia_close(term);
1878 done = EINA_TRUE;
1879 }
1880 }
1881 }
1882 else
1883 {
1884 Term_Container *tc = (Term_Container*) wn;
1885
1886 term = tc->focused_term_get(tc);
1887 if (!term)
1888 {
1889 DBG("no focused term");
1890 return;
1891 }
1892 if (term_has_popmedia(term) && !strcmp(ev->key, "Escape"))
1893 {
1894 term_popmedia_close(term);
1895 done = EINA_TRUE;
1896 }
1897 }
1898 if (done)
1899 {
1900 keyin_compose_seq_reset(&wn->khdl);
1901 goto end;
1902 }
1903
1904 /* 4th/ Handle key bindings */
1905 done = EINA_FALSE;
1906 if (wn->group_input)
1907 {
1908 wn->group_once_handled = EINA_FALSE;
1909 GROUPED_INPUT_TERM_FOREACH(wn, l, term)
1910 {
1911 done = keyin_handle_key_binding(term->termio, ev, ctrl, alt,
1912 shift, win, meta, hyper);
1913 if (!wn->group_input)
1914 return;
1915 }
1916 }
1917 else
1918 {
1919 Term_Container *tc = (Term_Container*) wn;
1920
1921 term = tc->focused_term_get(tc);
1922 if (!term)
1923 return;
1924 done = keyin_handle_key_binding(term->termio, ev, ctrl, alt,
1925 shift, win, meta, hyper);
1926 }
1927 if (done)
1928 {
1929 keyin_compose_seq_reset(&wn->khdl);
1930 goto end;
1931 }
1932 done = EINA_FALSE;
1933
1934 /* 5th/ Composing */
1935 if (wn->khdl.imf)
1936 {
1937 // EXCEPTION. Don't filter modifiers alt+shift -> breaks emacs
1938 // and jed (alt+shift+5 for search/replace for example)
1939 // Don't filter modifiers alt, is used by shells
1940 if ((!alt) && (!ctrl))
1941 {
1942 Ecore_IMF_Event_Key_Down imf_ev;
1943
1944 ecore_imf_evas_event_key_down_wrap(ev, &imf_ev);
1945 if (!wn->khdl.composing)
1946 {
1947 if (ecore_imf_context_filter_event(wn->khdl.imf,
1948 ECORE_IMF_EVENT_KEY_DOWN,
1949 (Ecore_IMF_Event *)&imf_ev))
1950 goto end;
1951 }
1952 }
1953 }
1954 if (!wn->khdl.composing)
1955 {
1956 Ecore_Compose_State state;
1957 char *compres = NULL;
1958
1959 keyin_compose_seq_reset(&wn->khdl);
1960 wn->khdl.seq = eina_list_append(wn->khdl.seq,
1961 eina_stringshare_add(ev->key));
1962 state = ecore_compose_get(wn->khdl.seq, &compres);
1963 if (state == ECORE_COMPOSE_MIDDLE)
1964 wn->khdl.composing = EINA_TRUE;
1965 else
1966 wn->khdl.composing = EINA_FALSE;
1967 if (!wn->khdl.composing)
1968 keyin_compose_seq_reset(&wn->khdl);
1969 else
1970 goto end;
1971 }
1972 else
1973 {
1974 Ecore_Compose_State state;
1975 char *compres = NULL;
1976
1977 if (key_is_modifier(ev->key))
1978 goto end;
1979 wn->khdl.seq = eina_list_append(wn->khdl.seq,
1980 eina_stringshare_add(ev->key));
1981 state = ecore_compose_get(wn->khdl.seq, &compres);
1982 if (state == ECORE_COMPOSE_NONE)
1983 keyin_compose_seq_reset(&wn->khdl);
1984 else if (state == ECORE_COMPOSE_DONE)
1985 {
1986 keyin_compose_seq_reset(&wn->khdl);
1987 if (compres)
1988 {
1989 int len = strlen(compres);
1990 if (wn->group_input)
1991 {
1992 GROUPED_INPUT_TERM_FOREACH(wn, l, term)
1993 {
1994 ty = termio_pty_get(term->termio);
1995 if (ty && termpty_can_handle_key(ty, &wn->khdl, ev))
1996 termpty_write(ty, compres, len);
1997 }
1998 }
1999 else
2000 {
2001 ty = termio_pty_get(term->termio);
2002 if (ty && termpty_can_handle_key(ty, &wn->khdl, ev))
2003 termpty_write(ty, compres, len);
2004 }
2005 free(compres);
2006 compres = NULL;
2007 }
2008 goto end;
2009 }
2010 else
2011 goto end;
2012 }
2013
2014 /* 6th/ send key to pty */
2015 if (wn->group_input)
2016 {
2017 GROUPED_INPUT_TERM_FOREACH(wn, l, term)
2018 {
2019 ty = termio_pty_get(term->termio);
2020 if (ty && termpty_can_handle_key(ty, &wn->khdl, ev))
2021 keyin_handle_key_to_pty(ty, ev, alt, shift, ctrl);
2022 }
2023 }
2024 else
2025 {
2026 ty = termio_pty_get(term->termio);
2027 DBG("ty:%p", ty);
2028 if (ty && termpty_can_handle_key(ty, &wn->khdl, ev))
2029 keyin_handle_key_to_pty(ty, ev, alt, shift, ctrl);
2030 }
2031
2032 /* 7th: specifics: jump on keypress / flicker on key */
2033 end:
2034 if (wn->group_input)
2035 {
2036 GROUPED_INPUT_TERM_FOREACH(wn, l, term)
2037 {
2038 if (term)
2039 termio_key_down(term->termio, ev, done);
2040 }
2041 }
2042 else
2043 {
2044 if (term)
2045 termio_key_down(term->termio, ev, done);
2046 }
2047 }
2048
2049 static void
_cb_win_mouse_down(void * data,Evas * _e EINA_UNUSED,Evas_Object * _obj EINA_UNUSED,void * event)2050 _cb_win_mouse_down(void *data,
2051 Evas *_e EINA_UNUSED,
2052 Evas_Object *_obj EINA_UNUSED,
2053 void *event)
2054 {
2055 Win *wn = data;
2056 Evas_Event_Mouse_Down *ev = event;
2057 Term *term, *term_mouse;
2058 Term_Container *tc = (Term_Container*) wn;
2059 Term_Container *tc_child;
2060
2061 if (wn->on_popover || wn->group_input)
2062 return;
2063
2064 /* Focus In event will handle that */
2065 if (!tc->is_focused)
2066 return;
2067
2068 term_mouse = tc->find_term_at_coords(tc, ev->canvas.x, ev->canvas.y);
2069 term = tc->focused_term_get(tc);
2070 if (term_mouse == term)
2071 return;
2072
2073 if (term)
2074 {
2075 tc_child = term->container;
2076 tc_child->unfocus(tc_child, tc);
2077 }
2078
2079 tc_child = term_mouse->container;
2080 DBG("focus tc_child:%p", tc_child);
2081 tc_child->focus(tc_child, tc);
2082 }
2083
2084 static Eina_Bool
_hide_cursor(void * data)2085 _hide_cursor(void *data)
2086 {
2087 Win *wn = data;
2088
2089 wn->hide_cursor_timer = NULL;
2090 for_each_term_do(wn, &_set_cursor, (void*)"blank");
2091 return ECORE_CALLBACK_CANCEL;
2092 }
2093
2094 static void
_cb_win_mouse_move(void * data,Evas * _e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event)2095 _cb_win_mouse_move(void *data,
2096 Evas *_e EINA_UNUSED,
2097 Evas_Object *obj EINA_UNUSED,
2098 void *event)
2099 {
2100 Win *wn = data;
2101 Evas_Event_Mouse_Move *ev = event;
2102 Term *term, *term_mouse;
2103 Term_Container *tc = (Term_Container*) wn;
2104 Term_Container *tc_child = NULL;
2105
2106 if (wn->on_popover)
2107 return;
2108
2109 if (wn->config->hide_cursor < CONFIG_CURSOR_IDLE_TIMEOUT_MAX)
2110 {
2111 if (wn->hide_cursor_timer)
2112 {
2113 ecore_timer_interval_set(wn->hide_cursor_timer,
2114 wn->config->hide_cursor);
2115 }
2116 else
2117 {
2118 for_each_term_do(wn, &_set_cursor, NULL);
2119 wn->hide_cursor_timer = ecore_timer_add(
2120 wn->config->hide_cursor, _hide_cursor, wn);
2121 }
2122 }
2123
2124 if (wn->group_input || !tc->is_focused || !wn->config->mouse_over_focus)
2125 return;
2126
2127 term_mouse = tc->find_term_at_coords(tc,
2128 ev->cur.canvas.x, ev->cur.canvas.y);
2129 term = tc->focused_term_get(tc);
2130 if (term_mouse == term)
2131 return;
2132
2133 DBG("mouse move");
2134 if (term)
2135 {
2136 tc_child = term->container;
2137 tc_child->unfocus(tc_child, tc);
2138 }
2139
2140 tc_child = term_mouse->container;
2141 DBG("need to focus");
2142 tc_child->focus(tc_child, tc);
2143 }
2144
2145 static Eina_Bool
_config_font_size_set(Term * term,void * data EINA_UNUSED)2146 _config_font_size_set(Term *term, void *data EINA_UNUSED)
2147 {
2148 Config *config = termio_config_get(term->termio);
2149
2150 termio_font_size_set(term->termio, config->font.size);
2151 return ECORE_CALLBACK_PASS_ON;
2152 }
2153
2154 static Eina_Bool
_cb_elm_config_change(void * data,int event EINA_UNUSED,void * info EINA_UNUSED)2155 _cb_elm_config_change(void *data, int event EINA_UNUSED, void *info EINA_UNUSED)
2156 {
2157 Win *wn = data;
2158
2159 for_each_term_do(wn, &_config_font_size_set, NULL);
2160 return ECORE_CALLBACK_PASS_ON;
2161 }
2162
2163 static Eina_Bool
_win_is_visible(const Term_Container * tc,const Term_Container * _child EINA_UNUSED)2164 _win_is_visible(const Term_Container *tc, const Term_Container *_child EINA_UNUSED)
2165 {
2166 assert (tc->type == TERM_CONTAINER_TYPE_WIN);
2167 return EINA_TRUE;
2168 }
2169
2170 Win *
win_new(const char * name,const char * role,const char * title,const char * icon_name,Config * config,Eina_Bool fullscreen,Eina_Bool iconic,Eina_Bool borderless,Eina_Bool override,Eina_Bool maximized)2171 win_new(const char *name, const char *role, const char *title,
2172 const char *icon_name, Config *config,
2173 Eina_Bool fullscreen, Eina_Bool iconic,
2174 Eina_Bool borderless, Eina_Bool override,
2175 Eina_Bool maximized)
2176 {
2177 Win *wn;
2178 Evas_Object *o;
2179 Term_Container *tc;
2180
2181 wn = calloc(1, sizeof(Win));
2182 if (!wn) return NULL;
2183
2184 wn->win = win_add(name, role, title, icon_name);
2185 if (!wn->win)
2186 {
2187 free(wn);
2188 return NULL;
2189 }
2190
2191 if (_win_log_dom < 0)
2192 {
2193 _win_log_dom = eina_log_domain_register("win", NULL);
2194 if (_win_log_dom < 0)
2195 EINA_LOG_CRIT("Could not create logging domain '%s'", "win");
2196 }
2197
2198 tc = (Term_Container*) wn;
2199 tc->term_next = _win_term_next;
2200 tc->term_prev = _win_term_prev;
2201 tc->term_up = _win_term_up;
2202 tc->term_down = _win_term_down;
2203 tc->term_left = _win_term_left;
2204 tc->term_right = _win_term_right;
2205 tc->term_first = _win_term_first;
2206 tc->term_last = _win_term_last;
2207 tc->focused_term_get = _win_focused_term_get;
2208 tc->get_evas_object = _win_get_evas_object;
2209 tc->split = _win_split;
2210 tc->split_direction = _win_split_direction;
2211 tc->find_term_at_coords = _win_find_term_at_coords;
2212 tc->size_eval = _win_size_eval;
2213 tc->swallow = _win_swallow;
2214 tc->focus = _win_focus;
2215 tc->unfocus = _win_unfocus;
2216 tc->set_title = _win_set_title;
2217 tc->bell = _win_bell;
2218 tc->close = _win_close;
2219 tc->update = _win_update;
2220 tc->is_visible = _win_is_visible;
2221 tc->detach = NULL;
2222 tc->title = eina_stringshare_add(title? title : "Terminology");
2223 tc->type = TERM_CONTAINER_TYPE_WIN;
2224 tc->wn = wn;
2225
2226 config_default_font_set(config, evas_object_evas_get(wn->win));
2227
2228 wn->config = config_fork(config);
2229
2230 evas_object_event_callback_add(wn->win, EVAS_CALLBACK_DEL, _cb_del, wn);
2231
2232 if (fullscreen) elm_win_fullscreen_set(wn->win, EINA_TRUE);
2233 if (iconic) elm_win_iconified_set(wn->win, EINA_TRUE);
2234 if (borderless) elm_win_borderless_set(wn->win, EINA_TRUE);
2235 if (override) elm_win_override_set(wn->win, EINA_TRUE);
2236 if (maximized) elm_win_maximized_set(wn->win, EINA_TRUE);
2237
2238 wn->backbg = o = evas_object_rectangle_add(evas_object_evas_get(wn->win));
2239 evas_object_color_set(o, 0, 0, 0, 255);
2240 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
2241 evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
2242 elm_win_resize_object_add(wn->win, o);
2243 evas_object_show(o);
2244
2245 wn->conform = o = elm_conformant_add(wn->win);
2246 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
2247 evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
2248 elm_win_resize_object_add(wn->win, o);
2249 evas_object_show(o);
2250
2251 wn->base = o = elm_layout_add(wn->win);
2252 elm_object_focus_allow_set(o, EINA_TRUE);
2253 theme_apply(o, config, "terminology/base", NULL, NULL, EINA_TRUE);
2254 evas_object_propagate_events_set(o, EINA_FALSE);
2255 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
2256 evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
2257 elm_object_content_set(wn->conform, o);
2258
2259 evas_object_smart_callback_add(wn->win, "focus,in", _cb_win_focus_in, wn);
2260 evas_object_smart_callback_add(wn->win, "focus,out", _cb_win_focus_out, wn);
2261
2262 evas_object_event_callback_add(wn->base,
2263 EVAS_CALLBACK_KEY_DOWN,
2264 _cb_win_key_down,
2265 wn);
2266 evas_object_event_callback_add(wn->base,
2267 EVAS_CALLBACK_KEY_UP,
2268 _cb_win_key_up,
2269 wn);
2270 evas_object_event_callback_add(wn->base,
2271 EVAS_CALLBACK_MOUSE_DOWN,
2272 _cb_win_mouse_down,
2273 wn);
2274 evas_object_event_callback_add(wn->base,
2275 EVAS_CALLBACK_MOUSE_MOVE,
2276 _cb_win_mouse_move,
2277 wn);
2278 evas_object_show(o);
2279 elm_object_focus_highlight_style_set(o, "blank");
2280 elm_object_focus_set(o, EINA_TRUE);
2281
2282 if (ecore_imf_init())
2283 {
2284 const char *imf_id = ecore_imf_context_default_id_get();
2285 Evas *e;
2286
2287 if (!imf_id)
2288 wn->khdl.imf = NULL;
2289 else
2290 {
2291 const Ecore_IMF_Context_Info *imf_info;
2292
2293 imf_info = ecore_imf_context_info_by_id_get(imf_id);
2294 if ((!imf_info->canvas_type) ||
2295 (strcmp(imf_info->canvas_type, "evas") == 0))
2296 wn->khdl.imf = ecore_imf_context_add(imf_id);
2297 else
2298 {
2299 imf_id = ecore_imf_context_default_id_by_canvas_type_get("evas");
2300 if (imf_id)
2301 wn->khdl.imf = ecore_imf_context_add(imf_id);
2302 }
2303 }
2304
2305 if (!wn->khdl.imf)
2306 goto imf_done;
2307
2308 e = evas_object_evas_get(o);
2309 ecore_imf_context_client_window_set
2310 (wn->khdl.imf, (void *)ecore_evas_window_get(ecore_evas_ecore_evas_get(e)));
2311 ecore_imf_context_client_canvas_set(wn->khdl.imf, e);
2312
2313 ecore_imf_context_event_callback_add
2314 (wn->khdl.imf, ECORE_IMF_CALLBACK_COMMIT, _imf_event_commit_cb, wn);
2315 ecore_imf_context_event_callback_add
2316 (wn->khdl.imf, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, _imf_event_delete_surrounding_cb, wn);
2317 ecore_imf_context_event_callback_add
2318 (wn->khdl.imf, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, _imf_event_preedit_changed_cb, wn);
2319 /* make IMF usable by a terminal - no preedit, prediction... */
2320 ecore_imf_context_prediction_allow_set
2321 (wn->khdl.imf, EINA_FALSE);
2322 ecore_imf_context_autocapital_type_set
2323 (wn->khdl.imf, ECORE_IMF_AUTOCAPITAL_TYPE_NONE);
2324 ecore_imf_context_input_panel_layout_set
2325 (wn->khdl.imf, ECORE_IMF_INPUT_PANEL_LAYOUT_TERMINAL);
2326 ecore_imf_context_input_mode_set
2327 (wn->khdl.imf, ECORE_IMF_INPUT_MODE_FULL);
2328 ecore_imf_context_input_panel_language_set
2329 (wn->khdl.imf, ECORE_IMF_INPUT_PANEL_LANG_ALPHABET);
2330 ecore_imf_context_input_panel_return_key_type_set
2331 (wn->khdl.imf, ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT);
2332 imf_done:
2333 if (wn->khdl.imf)
2334 DBG("Ecore IMF Setup");
2335 else
2336 WRN(_("Ecore IMF failed"));
2337
2338 }
2339
2340 if (wn->config->hide_cursor < CONFIG_CURSOR_IDLE_TIMEOUT_MAX)
2341 {
2342 wn->hide_cursor_timer = ecore_timer_add(
2343 wn->config->hide_cursor, _hide_cursor, wn);
2344 }
2345
2346 wins = eina_list_append(wins, wn);
2347
2348 wn->tc.is_focused = EINA_TRUE;
2349
2350 wn->config_elm_handler = ecore_event_handler_add
2351 (ELM_EVENT_CONFIG_ALL_CHANGED, _cb_elm_config_change, wn);
2352 return wn;
2353 }
2354
2355 void
term_close(Evas_Object * win,Evas_Object * term,Eina_Bool hold_if_requested)2356 term_close(Evas_Object *win, Evas_Object *term, Eina_Bool hold_if_requested)
2357 {
2358 Term *tm;
2359 Term_Container *tc;
2360 Win *wn = win_evas_object_to_win(win);
2361
2362 if (!wn)
2363 return;
2364
2365 tm = evas_object_data_get(term, "term");
2366 if (!tm)
2367 return;
2368
2369 if (tm->hold && hold_if_requested)
2370 return;
2371
2372 wn->terms = eina_list_remove(wn->terms, tm);
2373 tc = tm->container;
2374
2375 tc->close(tc, tc);
2376
2377 term_unref(tm);
2378 }
2379
2380 /* Returns True if action is permitted */
2381 Eina_Bool
win_is_group_action_handled(Win * wn)2382 win_is_group_action_handled(Win *wn)
2383 {
2384 DBG("wn->group_input:%d wn->group_once_handled:%d wn:%p",
2385 wn->group_input, wn->group_once_handled, wn);
2386 if (!wn->group_input)
2387 return EINA_FALSE;
2388 if (wn->group_once_handled)
2389 return EINA_TRUE;
2390 wn->group_once_handled = EINA_TRUE;
2391 return EINA_FALSE;
2392 }
2393
2394 Eina_Bool
win_is_group_input(const Win * wn)2395 win_is_group_input(const Win *wn)
2396 {
2397 return wn->group_input;
2398 }
2399
2400
2401
2402 static void
_win_toggle_group(Win * wn)2403 _win_toggle_group(Win *wn)
2404 {
2405 Eina_List *l;
2406 Term *term;
2407
2408 DBG("WIN TOGGLE");
2409 if (!wn->group_input)
2410 {
2411 GROUPED_INPUT_TERM_FOREACH(wn, l, term)
2412 {
2413 elm_layout_signal_emit(term->bg, "focus,in", "terminology");
2414 elm_layout_signal_emit(term->bg, "grouped,on", "terminology");
2415 if (term->tab_inactive)
2416 edje_object_signal_emit(term->tab_inactive,
2417 "grouped,on", "terminology");
2418 termio_event_feed_mouse_in(term->termio);
2419 termio_focus_in(term->termio);
2420 }
2421 wn->group_input = EINA_TRUE;
2422 DBG("GROUP INPUT is now TRUE");
2423 }
2424 else
2425 {
2426 wn->group_input = EINA_FALSE;
2427 DBG("GROUP INPUT is now FALSE");
2428 /* Better disable it for all of them in case of change of policy
2429 * between only visible or all.
2430 * Using the GROUPED_INPUT_TERM_FOREACH macro would miss some terms */
2431 EINA_LIST_FOREACH(wn->terms, l, term)
2432 {
2433 elm_layout_signal_emit(term->bg, "focus,out", "terminology");
2434 elm_layout_signal_emit(term->bg, "grouped,off", "terminology");
2435 if (term->tab_inactive)
2436 edje_object_signal_emit(term->tab_inactive,
2437 "grouped,off", "terminology");
2438 termio_focus_out(term->termio);
2439 }
2440 term = wn->child->term_first(wn->child);
2441 wn->child->focus(wn->child, &wn->tc);
2442 }
2443 }
2444
2445
2446 void
win_toggle_all_group(Win * wn)2447 win_toggle_all_group(Win *wn)
2448 {
2449 wn->group_only_visible = EINA_FALSE;
2450 _win_toggle_group(wn);
2451 }
2452 void
win_toggle_visible_group(Win * wn)2453 win_toggle_visible_group(Win *wn)
2454 {
2455 wn->group_only_visible = EINA_TRUE;
2456 _win_toggle_group(wn);
2457 }
2458
2459 /* }}} */
2460 /* {{{ Splits */
2461
2462 static Term *
_split_term_next(const Term_Container * tc,const Term_Container * child)2463 _split_term_next(const Term_Container *tc, const Term_Container *child)
2464 {
2465 Split *split;
2466
2467 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
2468 split = (Split*) tc;
2469
2470 if (child == split->tc1)
2471 return split->tc2->term_first(split->tc2);
2472 else
2473 return tc->parent->term_next(tc->parent, tc);
2474 }
2475
2476 static Term *
_split_term_prev(const Term_Container * tc,const Term_Container * child)2477 _split_term_prev(const Term_Container *tc, const Term_Container *child)
2478 {
2479 Split *split;
2480
2481 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
2482 split = (Split*) tc;
2483
2484 if (child == split->tc2)
2485 return split->tc1->term_last(split->tc1);
2486 else
2487 return tc->parent->term_prev(tc->parent, tc);
2488 }
2489
2490 static Term *
_split_term_up(const Term_Container * tc,const Term_Container * child)2491 _split_term_up(const Term_Container *tc,
2492 const Term_Container *child)
2493 {
2494 Split *split;
2495
2496 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
2497 split = (Split*) tc;
2498
2499 if (child == split->tc2 && split->is_horizontal)
2500 return split->tc1->term_last(split->tc1);
2501 else
2502 return tc->parent->term_up(tc->parent, tc);
2503 }
2504
2505 static Term *
_split_term_down(const Term_Container * tc,const Term_Container * child)2506 _split_term_down(const Term_Container *tc,
2507 const Term_Container *child)
2508 {
2509 Split *split;
2510
2511 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
2512 split = (Split*) tc;
2513
2514 if (child == split->tc1 && split->is_horizontal)
2515 return split->tc2->term_first(split->tc2);
2516 else
2517 return tc->parent->term_down(tc->parent, tc);
2518 }
2519
2520 static Term *
_split_term_left(const Term_Container * tc,const Term_Container * child)2521 _split_term_left(const Term_Container *tc,
2522 const Term_Container *child)
2523 {
2524 Split *split;
2525
2526 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
2527 split = (Split*) tc;
2528
2529 if (child == split->tc2 && !split->is_horizontal)
2530 return split->tc1->term_last(split->tc1);
2531 else
2532 return tc->parent->term_left(tc->parent, tc);
2533 }
2534
2535 static Term *
_split_term_right(const Term_Container * tc,const Term_Container * child)2536 _split_term_right(const Term_Container *tc,
2537 const Term_Container *child)
2538 {
2539 Split *split;
2540
2541 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
2542 split = (Split*) tc;
2543
2544 if (child == split->tc1 && !split->is_horizontal)
2545 return split->tc2->term_first(split->tc2);
2546 else
2547 return tc->parent->term_right(tc->parent, tc);
2548 }
2549
2550 static Term *
_split_term_first(const Term_Container * tc)2551 _split_term_first(const Term_Container *tc)
2552 {
2553 Split *split;
2554
2555 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
2556 split = (Split*) tc;
2557
2558 return split->tc1->term_first(split->tc1);
2559 }
2560
2561 static Term *
_split_term_last(const Term_Container * tc)2562 _split_term_last(const Term_Container *tc)
2563 {
2564 Split *split;
2565
2566 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
2567 split = (Split*) tc;
2568
2569 return split->tc2->term_last(split->tc2);
2570 }
2571
2572 static Evas_Object *
_split_get_evas_object(const Term_Container * tc)2573 _split_get_evas_object(const Term_Container *tc)
2574 {
2575 Split *split;
2576
2577 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
2578 split = (Split*) tc;
2579
2580 return split->panes;
2581 }
2582
2583 static void
_split_size_eval(Term_Container * tc,Sizeinfo * info)2584 _split_size_eval(Term_Container *tc, Sizeinfo *info)
2585 {
2586 Evas_Coord mw = 0, mh = 0;
2587 Term_Container *tc1, *tc2;
2588 Sizeinfo inforet = {0, 0, 0, 0, 0, 0, 0, 0, 0};
2589 Split *split;
2590
2591 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
2592 split = (Split*) tc;
2593
2594 tc1 = split->tc1;
2595 tc2 = split->tc2;
2596
2597 info->min_w = 0;
2598 info->min_h = 0;
2599 info->req_w = 0;
2600 info->req_h = 0;
2601
2602 evas_object_size_hint_min_get(split->panes, &mw, &mh);
2603 info->bg_min_w = mw;
2604 info->bg_min_h = mh;
2605
2606 if (split->is_horizontal)
2607 {
2608 tc1->size_eval(tc1, &inforet);
2609 info->req |= inforet.req;
2610 mh -= inforet.min_h;
2611 if (info->req)
2612 {
2613 info->req_h += inforet.req_h;
2614 info->req_w = inforet.req_w;
2615 }
2616
2617 tc2->size_eval(tc2, &inforet);
2618 info->req |= inforet.req;
2619 mh -= inforet.min_h;
2620 if (info->req)
2621 {
2622 info->req_h += inforet.req_h;
2623 info->req_w = inforet.req_w;
2624 }
2625 info->req_h += mh;
2626 if (info->req)
2627 info->req_w += mw - inforet.min_w - inforet.step_x;
2628 }
2629 else
2630 {
2631 tc1->size_eval(tc1, &inforet);
2632 info->req |= inforet.req;
2633 mw -= inforet.min_w;
2634 if (info->req)
2635 {
2636 info->req_w += inforet.req_w;
2637 info->req_h = inforet.req_h;
2638 }
2639
2640 tc2->size_eval(tc2, &inforet);
2641 info->req |= inforet.req;
2642 mw -= inforet.min_w;
2643 if (info->req)
2644 {
2645 info->req_w += inforet.req_w;
2646 info->req_h = inforet.req_h;
2647 }
2648 info->req_w += mw;
2649 if (info->req)
2650 info->req_h += mh - inforet.min_h - inforet.step_y;
2651 }
2652 info->step_x = inforet.step_x;
2653 info->step_y = inforet.step_y;
2654 }
2655
2656 static void
_split_swallow(Term_Container * tc,Term_Container * orig,Term_Container * new_child)2657 _split_swallow(Term_Container *tc, Term_Container *orig,
2658 Term_Container *new_child)
2659 {
2660 Split *split;
2661 Evas_Object *o;
2662
2663 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
2664 split = (Split*) tc;
2665
2666 assert (orig && (orig == split->tc1 || orig == split->tc2));
2667
2668 if ((_tab_drag) && (_tab_drag->parent_type == TERM_CONTAINER_TYPE_SPLIT) &&
2669 (_tab_drag->other == orig))
2670 {
2671 _tab_drag->other = new_child;
2672 }
2673
2674 if (split->last_focus == orig)
2675 split->last_focus = new_child;
2676
2677 o = orig->get_evas_object(orig);
2678 evas_object_hide(o);
2679
2680 o = new_child->get_evas_object(new_child);
2681 if (split->tc1 == orig)
2682 {
2683 elm_object_part_content_unset(split->panes, PANES_TOP);
2684 elm_object_part_content_set(split->panes, PANES_TOP, o);
2685 split->tc1 = new_child;
2686 }
2687 else
2688 {
2689 elm_object_part_content_unset(split->panes, PANES_BOTTOM);
2690 elm_object_part_content_set(split->panes, PANES_BOTTOM, o);
2691 split->tc2 = new_child;
2692 }
2693 new_child->parent = tc;
2694 evas_object_show(o);
2695 evas_object_show(split->panes);
2696 }
2697
2698 static Term *
_split_focused_term_get(const Term_Container * tc)2699 _split_focused_term_get(const Term_Container *tc)
2700 {
2701 Split *split;
2702 Term *term = NULL;
2703
2704 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
2705 split = (Split*) tc;
2706
2707 if (tc->is_focused)
2708 term = split->last_focus->focused_term_get(split->last_focus);
2709 return term;
2710 }
2711
2712 static Term *
_split_find_term_at_coords(const Term_Container * tc,Evas_Coord mx,Evas_Coord my)2713 _split_find_term_at_coords(const Term_Container *tc,
2714 Evas_Coord mx, Evas_Coord my)
2715 {
2716 Split *split;
2717 Evas_Coord ox, oy, ow, oh;
2718 Evas_Object *o;
2719
2720 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
2721 split = (Split*) tc;
2722
2723 o = split->tc1->get_evas_object(split->tc1);
2724
2725 evas_object_geometry_get(o, &ox, &oy, &ow, &oh);
2726 if (ELM_RECTS_INTERSECT(ox, oy, ow, oh, mx, my, 1, 1))
2727 {
2728 tc = split->tc1;
2729 }
2730 else
2731 {
2732 tc = split->tc2;
2733 }
2734
2735 return tc->find_term_at_coords(tc, mx, my);
2736 }
2737
2738 static void
_split_close(Term_Container * tc,Term_Container * child)2739 _split_close(Term_Container *tc, Term_Container *child)
2740 {
2741 Split *split;
2742 Term_Container *parent, *other_child;
2743 Evas_Object *top, *bottom;
2744
2745 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
2746 split = (Split*) tc;
2747 assert ((child == split->tc1) || (child == split->tc2));
2748
2749 DBG("close");
2750
2751 if ((_tab_drag) && (_tab_drag->parent_type == TERM_CONTAINER_TYPE_SPLIT) &&
2752 (_tab_drag->other == child))
2753 {
2754 _tab_drag->other = tc->parent;
2755 }
2756
2757 top = elm_object_part_content_unset(split->panes, PANES_TOP);
2758 bottom = elm_object_part_content_unset(split->panes, PANES_BOTTOM);
2759 evas_object_hide(top);
2760 evas_object_hide(bottom);
2761
2762 parent = tc->parent;
2763 other_child = (child == split->tc1) ? split->tc2 : split->tc1;
2764 parent->swallow(parent, tc, other_child);
2765
2766 if (tc->is_focused)
2767 {
2768 child->unfocus(child, tc);
2769 other_child->focus(other_child, parent);
2770 }
2771
2772 evas_object_del(split->panes);
2773
2774 eina_stringshare_del(tc->title);
2775 free(tc);
2776 }
2777
2778 static void
_split_update(Term_Container * tc)2779 _split_update(Term_Container *tc)
2780 {
2781 Split *split;
2782
2783 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
2784 split = (Split*) tc;
2785
2786 split->tc1->update(split->tc1);
2787 split->tc2->update(split->tc2);
2788 }
2789
2790 static void
_split_focus(Term_Container * tc,Term_Container * relative)2791 _split_focus(Term_Container *tc, Term_Container *relative)
2792 {
2793 Split *split;
2794 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
2795 split = (Split*) tc;
2796
2797 DBG("tc:%p tc->is_focused:%d from_parent:%d",
2798 tc, tc->is_focused, tc->parent == relative);
2799
2800 if (!tc->parent)
2801 return;
2802
2803 if (tc->parent == relative)
2804 {
2805 /* top to bottom */
2806 if (!tc->is_focused)
2807 {
2808 Term_Container *last_focus = split->last_focus;
2809 Term_Container *other = (split->tc1 == last_focus) ?
2810 split->tc2 : split->tc1;
2811
2812 tc->is_focused = EINA_TRUE;
2813 other->unfocus(other, tc);
2814 last_focus->focus(last_focus, tc);
2815 }
2816 }
2817 else
2818 {
2819 /* bottom to top */
2820 if (split->last_focus != relative)
2821 split->last_focus->unfocus(split->last_focus, tc);
2822 split->last_focus = relative;
2823 if (!tc->is_focused)
2824 {
2825 /* was not focused, bring focus up */
2826 tc->is_focused = EINA_TRUE;
2827 tc->parent->focus(tc->parent, tc);
2828 }
2829 }
2830 }
2831
2832 static void
_split_unfocus(Term_Container * tc,Term_Container * relative)2833 _split_unfocus(Term_Container *tc, Term_Container *relative)
2834 {
2835 Split *split;
2836 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
2837 split = (Split*) tc;
2838
2839 DBG("tc:%p tc->is_focused:%d from_parent:%d",
2840 tc, tc->is_focused, tc->parent == relative);
2841 if (!tc->is_focused)
2842 return;
2843
2844 tc->is_focused = EINA_FALSE;
2845 if (tc->parent == relative)
2846 split->last_focus->unfocus(split->last_focus, tc);
2847 else
2848 tc->parent->unfocus(tc->parent, tc);
2849 }
2850
2851 static void
_split_set_title(Term_Container * tc,Term_Container * child,const char * title)2852 _split_set_title(Term_Container *tc, Term_Container *child,
2853 const char *title)
2854 {
2855 Split *split;
2856
2857 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
2858 split = (Split*) tc;
2859
2860 if (child == split->last_focus)
2861 {
2862 eina_stringshare_del(tc->title);
2863 tc->title = eina_stringshare_ref(title);
2864 tc->parent->set_title(tc->parent, tc, title);
2865 }
2866 }
2867
2868 static void
_split_bell(Term_Container * tc,Term_Container * _child EINA_UNUSED)2869 _split_bell(Term_Container *tc,
2870 Term_Container *_child EINA_UNUSED)
2871 {
2872 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
2873
2874 if (tc->is_focused)
2875 return;
2876
2877 tc->parent->bell(tc->parent, tc);
2878 }
2879
2880 static void
_split_split(Term_Container * tc,Term_Container * child,Term * from,const char * cmd,Eina_Bool is_horizontal)2881 _split_split(Term_Container *tc, Term_Container *child,
2882 Term *from,
2883 const char *cmd, Eina_Bool is_horizontal)
2884 {
2885 Split *split;
2886 Win *wn;
2887 Term *tm_new, *tm;
2888 char *wdir = NULL;
2889 char buf[PATH_MAX];
2890 Term_Container *tc_split, *tc_solo_new;
2891 Evas_Object *obj_split;
2892 Eina_Bool child_is_focused;
2893
2894 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
2895 split = (Split *)tc;
2896 wn = tc->wn;
2897
2898 if (!_term_container_is_splittable(tc, is_horizontal))
2899 return;
2900
2901 // copy the current path to wdir if we should change the directory,
2902 // passing wdir NULL otherwise:
2903 if (wn->config->changedir_to_current)
2904 {
2905 if (from)
2906 tm = from;
2907 else
2908 tm = child->focused_term_get(child);
2909 if (tm && termio_cwd_get(tm->termio, buf, sizeof(buf)))
2910 wdir = buf;
2911 }
2912 tm_new = term_new(wn, wn->config,
2913 cmd, wn->config->login_shell, wdir,
2914 80, 24, EINA_FALSE, NULL);
2915 tc_solo_new = _solo_new(tm_new, wn);
2916 evas_object_data_set(tm_new->termio, "sizedone", tm_new->termio);
2917
2918 if (child == split->tc1)
2919 elm_object_part_content_unset(split->panes, PANES_TOP);
2920 else
2921 elm_object_part_content_unset(split->panes, PANES_BOTTOM);
2922
2923 child_is_focused = child->is_focused;
2924
2925 /* force unfocus animation */
2926 tc_solo_new->is_focused = EINA_TRUE;
2927 tc_solo_new->unfocus(tc_solo_new, NULL);
2928
2929 tc_split = _split_new(child, tc_solo_new, 0.5, is_horizontal);
2930
2931 obj_split = tc_split->get_evas_object(tc_split);
2932
2933 tc_split->is_focused = child_is_focused;
2934 tc->swallow(tc, child, tc_split);
2935
2936 if (wn->config->show_tabs)
2937 {
2938 _solo_tab_show(tc_solo_new);
2939 }
2940
2941 child->unfocus(child, tc_split);
2942 tc_split->focus(tc_split, tc_solo_new);
2943 tc_solo_new->focus(tc_solo_new, tc_split);
2944
2945 evas_object_show(obj_split);
2946 _focus_validator();
2947 }
2948
2949 static int
_split_split_direction(Term_Container * tc,Term_Container * child_orig,Term_Container * child_new,Split_Direction direction)2950 _split_split_direction(Term_Container *tc,
2951 Term_Container *child_orig,
2952 Term_Container *child_new,
2953 Split_Direction direction)
2954 {
2955 Split *split;
2956 Win *wn;
2957 Term_Container *child1, *child2, *tc_split;
2958 Eina_Bool is_horizontal =
2959 (direction == SPLIT_DIRECTION_LEFT) || (direction == SPLIT_DIRECTION_RIGHT) ?
2960 EINA_FALSE : EINA_TRUE;
2961
2962 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
2963 split = (Split *)tc;
2964 wn = tc->wn;
2965
2966 if (!_term_container_is_splittable(tc, is_horizontal))
2967 {
2968 ERR("term is not splittable");
2969 return -1;
2970 }
2971
2972 if ((direction == SPLIT_DIRECTION_TOP) ||
2973 (direction == SPLIT_DIRECTION_LEFT))
2974 {
2975 child1 = child_new;
2976 child2 = child_orig;
2977 }
2978 else
2979 {
2980 child1 = child_orig;
2981 child2 = child_new;
2982 }
2983
2984 if (child_orig == split->tc1)
2985 elm_object_part_content_unset(split->panes, PANES_TOP);
2986 else
2987 elm_object_part_content_unset(split->panes, PANES_BOTTOM);
2988
2989 wn->tc.unfocus(&wn->tc, NULL); /* unfocus from top */
2990
2991 tc_split = _split_new(child1, child2, 0.5, is_horizontal);
2992
2993 if (wn->config->show_tabs)
2994 {
2995 if (child_orig->type == TERM_CONTAINER_TYPE_SOLO)
2996 {
2997 _solo_tab_show(child_orig);
2998 }
2999 _solo_tab_show(child_new);
3000 }
3001
3002 tc_split->is_focused = tc->is_focused;
3003 tc->swallow(tc, child_orig, tc_split);
3004
3005 child_new->focus(child_new, NULL); /* refocus from bottom */
3006
3007 return 0;
3008 }
3009
3010 static Eina_Bool
_split_is_visible(const Term_Container * tc,const Term_Container * _child EINA_UNUSED)3011 _split_is_visible(const Term_Container *tc,
3012 const Term_Container *_child EINA_UNUSED)
3013 {
3014 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
3015 /* Could return True with the current design because splits are at a higher
3016 * level than tabs */
3017 return tc->parent->is_visible(tc->parent, tc);
3018 }
3019
3020 static void
_split_detach(Term_Container * tc,Term_Container * solo_child)3021 _split_detach(Term_Container *tc, Term_Container *solo_child)
3022 {
3023 Evas_Object *o;
3024 assert (tc->type == TERM_CONTAINER_TYPE_SPLIT);
3025 assert (solo_child->type == TERM_CONTAINER_TYPE_SOLO);
3026
3027 _split_close(tc, solo_child);
3028 solo_child->is_focused = EINA_FALSE;
3029
3030 o = solo_child->get_evas_object(solo_child);
3031 evas_object_hide(o);
3032 solo_child->parent = (Term_Container*) solo_child->wn;
3033 }
3034
3035 static Term_Container *
_split_new(Term_Container * tc1,Term_Container * tc2,double left_size,Eina_Bool is_horizontal)3036 _split_new(Term_Container *tc1, Term_Container *tc2,
3037 double left_size,
3038 Eina_Bool is_horizontal)
3039 {
3040 Evas_Object *o;
3041 Term_Container *tc = NULL;
3042 Split *split = NULL;
3043 split = calloc(1, sizeof(Split));
3044 if (!split)
3045 {
3046 free(split);
3047 return NULL;
3048 }
3049
3050 DBG("split new %p 1:%p 2:%p (1 is %sfocused) (2 is %sfocused)", split, tc1, tc2,
3051 tc1->is_focused ? "" : "not ",
3052 tc2->is_focused ? "" : "not ");
3053
3054 tc = (Term_Container*)split;
3055 tc->term_next = _split_term_next;
3056 tc->term_prev = _split_term_prev;
3057 tc->term_up = _split_term_up;
3058 tc->term_down = _split_term_down;
3059 tc->term_left = _split_term_left;
3060 tc->term_right = _split_term_right;
3061 tc->term_first = _split_term_first;
3062 tc->term_last = _split_term_last;
3063 tc->focused_term_get = _split_focused_term_get;
3064 tc->get_evas_object = _split_get_evas_object;
3065 tc->split = _split_split;
3066 tc->split_direction = _split_split_direction;
3067 tc->find_term_at_coords = _split_find_term_at_coords;
3068 tc->size_eval = _split_size_eval;
3069 tc->swallow = _split_swallow;
3070 tc->focus = _split_focus;
3071 tc->unfocus = _split_unfocus;
3072 tc->set_title = _split_set_title;
3073 tc->bell = _split_bell;
3074 tc->close = _split_close;
3075 tc->update = _split_update;
3076 tc->is_visible = _split_is_visible;
3077 tc->detach = _split_detach;
3078 tc->title = eina_stringshare_add("Terminology");
3079 tc->type = TERM_CONTAINER_TYPE_SPLIT;
3080
3081
3082 tc->parent = NULL;
3083 tc->wn = tc1->wn;
3084
3085 tc1->parent = tc2->parent = tc;
3086
3087 split->tc1 = tc1;
3088 split->tc2 = tc2;
3089 split->last_focus = tc2;
3090 if (tc1->is_focused)
3091 split->last_focus = tc1;
3092
3093 o = split->panes = elm_panes_add(tc1->wn->win);
3094 elm_object_style_set(o, "flush");
3095 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
3096 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
3097
3098 split->is_horizontal = is_horizontal;
3099 elm_panes_horizontal_set(o, split->is_horizontal);
3100
3101 elm_object_part_content_set(o, PANES_TOP,
3102 tc1->get_evas_object(tc1));
3103 elm_object_part_content_set(o, PANES_BOTTOM,
3104 tc2->get_evas_object(tc2));
3105 elm_panes_content_left_size_set(o, left_size);
3106
3107 tc->is_focused = tc1->is_focused | tc2->is_focused;
3108 assert(!(tc1->is_focused && tc2->is_focused));
3109 return tc;
3110 }
3111
3112 static void
_size_job(void * data)3113 _size_job(void *data)
3114 {
3115 Win *wn = data;
3116 Sizeinfo info = {0, 0, 0, 0, 0, 0, 0, 0, 0};
3117 Term_Container *tc = (Term_Container*) wn;
3118
3119 wn->size_job = NULL;
3120 tc->size_eval(tc, &info);
3121
3122 elm_win_size_step_set(wn->win, info.step_x, info.step_y);
3123 if (info.bg_min_w > 0 && info.bg_min_h > 0)
3124 {
3125 elm_win_size_base_set(wn->win,
3126 info.min_w, info.min_h);
3127 evas_object_size_hint_min_set(wn->backbg,
3128 info.bg_min_w,
3129 info.bg_min_h);
3130 if (info.req)
3131 evas_object_resize(wn->win, info.req_w, info.req_h);
3132 }
3133 }
3134
3135 void
win_sizing_handle(Win * wn)3136 win_sizing_handle(Win *wn)
3137 {
3138 if (wn->size_job)
3139 ecore_job_del(wn->size_job);
3140 _size_job(wn);
3141 }
3142
3143 static void
_cb_size_hint(void * data,Evas * _e EINA_UNUSED,Evas_Object * obj,void * _event EINA_UNUSED)3144 _cb_size_hint(void *data,
3145 Evas *_e EINA_UNUSED,
3146 Evas_Object *obj,
3147 void *_event EINA_UNUSED)
3148 {
3149 Term *term = data;
3150 Evas_Coord mw, mh, rw, rh, w = 0, h = 0;
3151 Evas_Object *edje_base = elm_layout_edje_get(term->core);
3152
3153 evas_object_size_hint_min_get(obj, &mw, &mh);
3154 evas_object_size_hint_request_get(obj, &rw, &rh);
3155 edje_object_size_min_calc(edje_base, &w, &h);
3156 evas_object_size_hint_min_set(term->core, w, h);
3157 edje_object_size_min_calc(term->bg_edj, &w, &h);
3158 evas_object_size_hint_min_set(term->bg, w, h);
3159 term->step_x = mw;
3160 term->step_y = mh;
3161 term->min_w = w - mw;
3162 term->min_h = h - mh;
3163 term->req_w = w - mw + rw;
3164 term->req_h = h - mh + rh;
3165
3166 if (term->wn->size_job)
3167 ecore_job_del(term->wn->size_job);
3168 term->wn->size_job = ecore_job_add(_size_job, term->wn);
3169 }
3170
3171 void
split_horizontally(Evas_Object * term,const char * cmd)3172 split_horizontally(Evas_Object *term,
3173 const char *cmd)
3174 {
3175 Term *tm;
3176 Term_Container *tc;
3177
3178 tm = evas_object_data_get(term, "term");
3179 if (!tm) return;
3180
3181 tc = tm->container;
3182 tc->split(tc, tc, tm, cmd, EINA_TRUE);
3183 }
3184
3185 void
split_vertically(Evas_Object * term,const char * cmd)3186 split_vertically(Evas_Object *term,
3187 const char *cmd)
3188 {
3189 Term *tm;
3190 Term_Container *tc;
3191
3192 tm = evas_object_data_get(term, "term");
3193 if (!tm) return;
3194
3195 tc = tm->container;
3196 tc->split(tc, tc, tm, cmd, EINA_FALSE);
3197 }
3198
3199 /* }}} */
3200 /* {{{ Tabs */
3201
3202 static Term *
_tab_item_to_term(const Tab_Item * tab_item)3203 _tab_item_to_term(const Tab_Item *tab_item)
3204 {
3205 Solo *solo;
3206
3207 assert (tab_item->tc->type == TERM_CONTAINER_TYPE_SOLO);
3208 solo = (Solo*)tab_item->tc;
3209 assert (solo->term);
3210 assert (solo->term->tab_item == tab_item);
3211 return solo->term;
3212 }
3213
3214 static void
_cb_tab_activate(void * data,Evas_Object * _obj EINA_UNUSED,const char * _sig EINA_UNUSED,const char * _src EINA_UNUSED)3215 _cb_tab_activate(void *data,
3216 Evas_Object *_obj EINA_UNUSED,
3217 const char *_sig EINA_UNUSED,
3218 const char *_src EINA_UNUSED)
3219 {
3220 Tab_Item *tab_item = data;
3221 Term *term = _tab_item_to_term(tab_item);
3222
3223 term_focus(term);
3224 }
3225
3226
3227 static void
_tabbar_clear(Term * term)3228 _tabbar_clear(Term *term)
3229 {
3230 if (term->tabbar.l.box)
3231 {
3232 elm_box_unpack_all(term->tabbar.l.box);
3233 evas_object_del(term->tabbar.l.box);
3234 term->tabbar.l.box = NULL;
3235 }
3236 if (term->tabbar.r.box)
3237 {
3238 elm_box_unpack_all(term->tabbar.r.box);
3239 evas_object_del(term->tabbar.r.box);
3240 term->tabbar.r.box = NULL;
3241 }
3242
3243 if (term->tab_spacer)
3244 {
3245 elm_layout_signal_emit(term->bg, "tabbar,off", "terminology");
3246 edje_object_message_signal_process(term->bg_edj);
3247 elm_layout_content_unset(term->bg, "terminology.tab");
3248 evas_object_del(term->tab_spacer);
3249 term->tab_spacer = NULL;
3250 }
3251 if (term->tab_inactive)
3252 {
3253 evas_object_hide(term->tab_inactive);
3254 edje_object_signal_callback_del(term->tab_inactive,
3255 "tab,activate", "terminology",
3256 _cb_tab_activate);
3257 }
3258 }
3259
3260 static void
_tab_item_free(Tab_Item * tab_item)3261 _tab_item_free(Tab_Item *tab_item)
3262 {
3263 Term *term;
3264
3265 if (!tab_item)
3266 return;
3267
3268 term = _tab_item_to_term(tab_item);
3269 term->tab_item = NULL;
3270 if (term->tab_inactive)
3271 edje_object_signal_callback_del(term->tab_inactive,
3272 "tab,activate", "terminology",
3273 _cb_tab_activate);
3274 free(tab_item);
3275 }
3276
3277 static void
_cb_tab_close(void * data,Evas_Object * _obj EINA_UNUSED,const char * _sig EINA_UNUSED,const char * _src EINA_UNUSED)3278 _cb_tab_close(void *data,
3279 Evas_Object *_obj EINA_UNUSED,
3280 const char *_sig EINA_UNUSED,
3281 const char *_src EINA_UNUSED)
3282 {
3283 Term *term = data;
3284 Win *wn = term->wn;
3285 Evas_Object *win = win_evas_object_get(wn);
3286
3287 term_close(win, term->termio, EINA_FALSE);
3288 }
3289
3290 static void
_cb_tab_title(void * data,Evas_Object * _obj EINA_UNUSED,const char * _sig EINA_UNUSED,const char * _src EINA_UNUSED)3291 _cb_tab_title(void *data,
3292 Evas_Object *_obj EINA_UNUSED,
3293 const char *_sig EINA_UNUSED,
3294 const char *_src EINA_UNUSED)
3295 {
3296 Term *term = data;
3297
3298 term_set_title(term);
3299 }
3300
3301
3302
3303 static void
_tabs_recompute_drag(Tabs * tabs)3304 _tabs_recompute_drag(Tabs *tabs)
3305 {
3306 Term *term = NULL;
3307 int n = eina_list_count(tabs->tabs);
3308 int idx = -1;
3309 Tab_Item *tab_item;
3310 Eina_List *l;
3311 double v1 = 0.0, v2 = 1.0;
3312
3313 EINA_LIST_FOREACH(tabs->tabs, l, tab_item)
3314 {
3315 idx++;
3316 if (tab_item == tabs->current)
3317 {
3318 term = _tab_item_to_term(tab_item);
3319 break;
3320 }
3321 }
3322 assert(term != NULL);
3323 if (n > 1)
3324 {
3325 v1 = (double)(idx) / (double)n;
3326 v2 = (double)(idx+1) / (double)n;
3327 }
3328 tabs->v1_orig = v1;
3329 tabs->v2_orig = v2;
3330 edje_object_part_drag_value_set(term->bg_edj, "terminology.tabl", v1, 0.0);
3331 edje_object_part_drag_value_set(term->bg_edj, "terminology.tabr", v2, 0.0);
3332 }
3333
3334 static Eina_Bool
_term_hdrag_on(Term * term,void * data EINA_UNUSED)3335 _term_hdrag_on(Term *term, void *data EINA_UNUSED)
3336 {
3337 elm_layout_signal_emit(term->bg, "hdrag,on", "terminology");
3338
3339 return ECORE_CALLBACK_PASS_ON;
3340 }
3341
3342 static Eina_Bool
_term_hdrag_off(Term * term,void * data EINA_UNUSED)3343 _term_hdrag_off(Term *term, void *data EINA_UNUSED)
3344 {
3345 elm_layout_signal_emit(term->bg, "hdrag,off", "terminology");
3346
3347 return ECORE_CALLBACK_PASS_ON;
3348 }
3349
3350 static void
_tab_drag_disable_anim_over(void)3351 _tab_drag_disable_anim_over(void)
3352 {
3353 if ((!_tab_drag) || (!_tab_drag->term_over) ||
3354 (_tab_drag->split_direction == SPLIT_DIRECTION_NONE))
3355 return;
3356
3357 switch (_tab_drag->split_direction)
3358 {
3359 case SPLIT_DIRECTION_LEFT:
3360 elm_layout_signal_emit(_tab_drag->term_over->bg,
3361 "drag_left,off", "terminology");
3362 break;
3363 case SPLIT_DIRECTION_RIGHT:
3364 elm_layout_signal_emit(_tab_drag->term_over->bg,
3365 "drag_right,off", "terminology");
3366 break;
3367 case SPLIT_DIRECTION_TOP:
3368 elm_layout_signal_emit(_tab_drag->term_over->bg,
3369 "drag_top,off", "terminology");
3370 break;
3371 case SPLIT_DIRECTION_BOTTOM:
3372 elm_layout_signal_emit(_tab_drag->term_over->bg,
3373 "drag_bottom,off", "terminology");
3374 break;
3375 case SPLIT_DIRECTION_TABS:
3376 elm_layout_signal_emit(_tab_drag->term_over->bg,
3377 "drag_over_tabs,off", "terminology");
3378 break;
3379 default:
3380 break;
3381 }
3382 elm_layout_signal_emit(_tab_drag->term_over->bg,
3383 "hdrag,off", "terminology");
3384 }
3385
3386 static void
_tab_drag_rollback_split(void)3387 _tab_drag_rollback_split(void)
3388 {
3389 Eina_Bool is_horizontal = _tab_drag->is_horizontal;
3390 Term_Container *tc_split = NULL;
3391 Term_Container *child1 = NULL, *child2 = NULL;
3392 Term_Container *other = _tab_drag->other;
3393 Term_Container *parent = NULL;
3394 Win *wn = _tab_drag->term->wn;
3395 Term_Container *tc_win = (Term_Container*)wn;
3396 Term_Container *tc = _tab_drag->term->container;
3397
3398 if (!_tab_drag->other)
3399 {
3400 other = wn->child;
3401 }
3402 parent = other->parent;
3403
3404 if (_tab_drag->is_first_child)
3405 {
3406 child1 = tc;
3407 child2 = other;
3408 }
3409 else
3410 {
3411 child1 = other;
3412 child2 = tc;
3413 }
3414
3415 assert(!tc->is_focused);
3416 tc_split = _split_new(child1, child2, _tab_drag->left_size, is_horizontal);
3417 parent->swallow(parent, other, tc_split);
3418 /* Ensure the other child is unfocused */
3419 other->unfocus(other, tc_split);
3420 /* Unfocus from the window down to a single term */
3421 tc_win->unfocus(tc_win, NULL);
3422 /* Focus the dragged term, up to the window */
3423 tc->focus(tc, NULL);
3424 }
3425
3426 static void
_tabs_attach(Term_Container * tc,Term_Container * tc_new)3427 _tabs_attach(Term_Container *tc, Term_Container *tc_new)
3428 {
3429 Tabs *tabs;
3430 Tab_Item *tab_item;
3431 Evas_Object *o;
3432 Evas_Coord x, y, w, h;
3433 Term_Container *tc_old, *tc_parent;
3434
3435 assert (tc->type == TERM_CONTAINER_TYPE_TABS);
3436 assert (tc_new->type == TERM_CONTAINER_TYPE_SOLO);
3437
3438 tabs = (Tabs*) tc;
3439
3440 tc_new->parent = tc;
3441 tab_item = tab_item_new(tabs, tc_new);
3442
3443 tc_parent = tc->parent;
3444 tc_old = tabs->current->tc;
3445 tc_old->unfocus(tc_old, tc);
3446 o = tc_old->get_evas_object(tc_old);
3447 evas_object_geometry_get(o, &x, &y, &w, &h);
3448 evas_object_hide(o);
3449 o = tc_new->get_evas_object(tc_new);
3450 evas_object_geometry_set(o, x, y, w, h);
3451 evas_object_show(o);
3452
3453 tc->swallow(tc, tc_old, tc_new);
3454 tabs->current = tab_item;
3455
3456 /* XXX: need to refresh parent */
3457 tc_parent->swallow(tc_parent, tc, tc);
3458
3459 if (tc->is_focused)
3460 tc_new->focus(tc_new, tc);
3461 else
3462 tc_new->unfocus(tc_new, tc);
3463 }
3464
3465
3466 static void
_solo_attach(Term_Container * tc,Term_Container * tc_to_add)3467 _solo_attach(Term_Container *tc, Term_Container *tc_to_add)
3468 {
3469 assert(tc->type == TERM_CONTAINER_TYPE_SOLO);
3470 assert(tc_to_add->type == TERM_CONTAINER_TYPE_SOLO);
3471
3472 if (tc->parent->type != TERM_CONTAINER_TYPE_TABS)
3473 _tabs_new(tc, tc->parent);
3474
3475 _tabs_attach(tc->parent, tc_to_add);
3476 assert(eina_list_count(((Tabs*)(tc->parent))->tabs) > 1);
3477 }
3478
3479 static void
_tab_drag_reparented(void)3480 _tab_drag_reparented(void)
3481 {
3482 assert(_tab_drag);
3483 _tab_drag->parent_type = TERM_CONTAINER_TYPE_UNKNOWN;
3484 }
3485
3486 static void
_term_on_horizontal_drag(void * data,Evas_Object * o EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)3487 _term_on_horizontal_drag(void *data,
3488 Evas_Object *o EINA_UNUSED,
3489 const char *emission EINA_UNUSED,
3490 const char *source EINA_UNUSED)
3491 {
3492 Eina_List *l, *next, *prev;
3493 int tab_active_idx;
3494 int n;
3495 Tabs *tabs;
3496 Tab_Item *tab_item;
3497 Tab_Item *item_moved;
3498 Term *term = data;
3499 Term_Container *tc = term->container;
3500 Term_Container *tc_parent = tc->parent;
3501 Term *term_moved;
3502 double v1, v2, m;
3503
3504 assert (tc->type == TERM_CONTAINER_TYPE_SOLO);
3505 if (tc->parent->type != TERM_CONTAINER_TYPE_TABS)
3506 {
3507 edje_object_part_drag_value_set(term->bg_edj, "terminology.tabl",
3508 0.0, 0.0);
3509 edje_object_part_drag_value_set(term->bg_edj, "terminology.tabr",
3510 1.0, 0.0);
3511 return;
3512 }
3513
3514 tabs = (Tabs*) tc_parent;
3515 n = eina_list_count(tabs->tabs);
3516 if (n <= 1)
3517 return;
3518
3519 tab_item = tabs->current;
3520
3521 _tab_drag_free();
3522
3523 tab_active_idx = -1;
3524 EINA_LIST_FOREACH(tabs->tabs, l, tab_item)
3525 {
3526 tab_active_idx++;
3527 if (tab_item == tabs->current)
3528 break;
3529 }
3530 tab_item = tabs->current;
3531
3532 edje_object_part_drag_value_get(term->bg_edj, "terminology.tabl",
3533 &v1, NULL);
3534 edje_object_part_drag_value_get(term->bg_edj, "terminology.tabr",
3535 &v2, NULL);
3536 m = 1.2 / ((double)(2 * n)); /* 1.2, to have some sense of hysteresis */
3537 while ((tab_active_idx < n - 1) &&
3538 ((v2 > (tabs->v2_orig + m)) ||
3539 ((v1 == v2) && (v2 > tabs->v2_orig))))
3540 {
3541 /* To the right */
3542 l = eina_list_nth_list(tabs->tabs, tab_active_idx);
3543 next = eina_list_next(l);
3544 item_moved = next->data;
3545 term_moved = _tab_item_to_term(item_moved);
3546 elm_box_unpack(term->tabbar.r.box, term_moved->tab_inactive);
3547 elm_box_pack_end(term->tabbar.l.box, term_moved->tab_inactive);
3548
3549 tabs->tabs = eina_list_remove_list(tabs->tabs, l);
3550 tabs->tabs = eina_list_append_relative_list(tabs->tabs,
3551 eina_list_data_get(l),
3552 next);
3553 _tabs_recompute_drag(tabs);
3554 tab_active_idx++;
3555 if (v2 <= tabs->v2_orig)
3556 return;
3557 }
3558 while ((tab_active_idx > 0) &&
3559 ((v1 < tabs->v1_orig - m) ||
3560 ((v1 == v2) && v1 < tabs->v1_orig)))
3561 {
3562 /* To the left */
3563 l = eina_list_nth_list(tabs->tabs, tab_active_idx);
3564 prev = eina_list_prev(l);
3565 item_moved = prev->data;
3566 term_moved = _tab_item_to_term(item_moved);
3567 elm_box_unpack(term->tabbar.l.box, term_moved->tab_inactive);
3568 elm_box_pack_start(term->tabbar.r.box, term_moved->tab_inactive);
3569
3570 tabs->tabs = eina_list_remove_list(tabs->tabs, prev);
3571 tabs->tabs = eina_list_append_relative_list(tabs->tabs,
3572 eina_list_data_get(prev),
3573 l);
3574 _tabs_recompute_drag(tabs);
3575 tab_active_idx--;
3576 }
3577 }
3578
3579 static void
_tabs_set_main_tab(Term * term,Tab_Item * tab_item)3580 _tabs_set_main_tab(Term *term,
3581 Tab_Item *tab_item)
3582 {
3583 if (!term->tab_spacer)
3584 {
3585 Evas_Coord w = 0, h = 0;
3586 Evas *canvas = evas_object_evas_get(term->bg);
3587
3588 term->tab_spacer = evas_object_rectangle_add(canvas);
3589 evas_object_color_set(term->tab_spacer, 0, 0, 0, 0);
3590 elm_coords_finger_size_adjust(1, &w, 1, &h);
3591 evas_object_size_hint_min_set(term->tab_spacer, w, h);
3592 elm_layout_content_set(term->bg, "terminology.tab", term->tab_spacer);
3593 }
3594 evas_object_show(term->tab_spacer);
3595 elm_layout_text_set(term->bg, "terminology.tab.title", tab_item->tc->title);
3596 elm_layout_signal_emit(term->bg, "tabbar,on", "terminology");
3597 elm_layout_signal_emit(term->bg, "tab_btn,on", "terminology");
3598 edje_object_message_signal_process(term->bg_edj);
3599 }
3600
3601 static Evas_Object*
_tab_inactive_get_or_create(Evas * canvas,Term * term,Tab_Item * tab_item)3602 _tab_inactive_get_or_create(Evas *canvas,
3603 Term *term,
3604 Tab_Item *tab_item)
3605 {
3606 Evas_Object *o;
3607 Evas_Coord w, h;
3608
3609 if (term->tab_inactive)
3610 {
3611 o = term->tab_inactive;
3612 goto created;
3613 }
3614
3615 term->tab_inactive = o = edje_object_add(canvas);
3616
3617 theme_apply(o, term->config, "terminology/tabbar_back",
3618 NULL, NULL, EINA_FALSE);
3619 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
3620 evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
3621 edje_object_size_min_calc(o, &w, &h);
3622 evas_object_size_hint_min_set(o, w, h);
3623 evas_object_data_set(o, "term", term);
3624
3625 created:
3626 edje_object_signal_callback_add(o, "tab,activate", "terminology",
3627 _cb_tab_activate, tab_item);
3628
3629 if (term->missed_bell)
3630 edje_object_signal_emit(o, "bell", "terminology");
3631 else
3632 edje_object_signal_emit(o, "bell,off", "terminology");
3633 edje_object_part_text_set(o, "terminology.title",
3634 tab_item->tc->title);
3635 return o;
3636 }
3637
3638
3639 static void
_tabbar_fill(Tabs * tabs)3640 _tabbar_fill(Tabs *tabs)
3641 {
3642 Eina_List *l;
3643 Eina_Bool after_current = EINA_FALSE;
3644 Tab_Item *tab_item;
3645 Term *main_term = _tab_item_to_term(tabs->current);
3646 Evas *canvas = evas_object_evas_get(main_term->bg);
3647
3648 EINA_LIST_FOREACH(tabs->tabs, l, tab_item)
3649 {
3650 Term *term = _tab_item_to_term(tab_item);
3651
3652 if (tab_item == tabs->current)
3653 {
3654 _tabs_set_main_tab(term, tab_item);
3655 assert(main_term == term);
3656 evas_object_hide(term->tab_inactive);
3657 edje_object_signal_callback_del(term->tab_inactive,
3658 "tab,activate", "terminology",
3659 _cb_tab_activate);
3660 after_current = EINA_TRUE;
3661 }
3662 else
3663 {
3664 Evas_Object *o;
3665
3666 _tabbar_clear(term);
3667
3668 o = _tab_inactive_get_or_create(canvas, term, tab_item);
3669 evas_object_show(o);
3670 if (after_current)
3671 elm_box_pack_end(main_term->tabbar.r.box, o);
3672 else
3673 elm_box_pack_end(main_term->tabbar.l.box, o);
3674 }
3675 }
3676 _tabs_recompute_drag(tabs);
3677 }
3678
3679 static void
_tabs_get_or_create_boxes(Term * term,Term * src)3680 _tabs_get_or_create_boxes(Term *term, Term *src)
3681 {
3682 Evas_Object *o;
3683
3684 assert(term->tabbar.l.box == NULL);
3685 assert(term->tabbar.r.box == NULL);
3686
3687 /* Left */
3688 if (src && src->tabbar.l.box)
3689 {
3690 term->tabbar.l.box = o = src->tabbar.l.box;
3691 elm_box_unpack_all(term->tabbar.l.box);
3692 src->tabbar.l.box = NULL;
3693 }
3694 else
3695 {
3696 term->tabbar.l.box = o = elm_box_add(term->bg);
3697 elm_box_horizontal_set(o, EINA_TRUE);
3698 elm_box_homogeneous_set(o, EINA_TRUE);
3699 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
3700 evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
3701 }
3702 elm_layout_content_set(term->bg, "terminology.tabl.content", o);
3703 evas_object_show(o);
3704
3705 /* Right */
3706 if (src && src->tabbar.r.box)
3707 {
3708 term->tabbar.r.box = o = src->tabbar.r.box;
3709 elm_box_unpack_all(term->tabbar.r.box);
3710 src->tabbar.r.box = NULL;
3711 }
3712 else
3713 {
3714 term->tabbar.r.box = o = elm_box_add(term->bg);
3715 elm_box_horizontal_set(o, EINA_TRUE);
3716 elm_box_homogeneous_set(o, EINA_TRUE);
3717 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
3718 evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
3719 }
3720 elm_layout_content_set(term->bg, "terminology.tabr.content", o);
3721 evas_object_show(o);
3722 }
3723
3724 static void
_tab_drag_rollback_win(void)3725 _tab_drag_rollback_win(void)
3726 {
3727 Term *term = _tab_drag->term;
3728 Win *wn = term->wn;
3729 Term_Container *tc_win = (Term_Container*)wn;
3730 Term_Container *tc = term->container;
3731
3732 if (term->unswallowed)
3733 elm_layout_content_set(term->bg, "terminology.content", term->core);
3734 term->unswallowed = EINA_FALSE;
3735
3736 tc_win->swallow(tc_win, NULL, tc);
3737 tc_win->unfocus(tc_win, NULL);
3738 tc->focus(tc, NULL);
3739
3740 _tab_drag_reparented();
3741 }
3742
3743 static void
_tab_drag_rollback_tabs(void)3744 _tab_drag_rollback_tabs(void)
3745 {
3746 Term *term = _tab_drag->term;
3747 Win *wn = term->wn;
3748 Term_Container *tc_win = (Term_Container*)wn;
3749 Term_Container *tc = term->container;
3750 Term_Container *tc_tabs = _tab_drag->tabs_child;
3751 int n;
3752 Tabs *tabs;
3753
3754 if (tc_tabs->type == TERM_CONTAINER_TYPE_TABS)
3755 {
3756 tabs = (Tabs*) tc_tabs;
3757
3758 /* reinsert at correct place */
3759 _solo_attach(tabs->current->tc, tc);
3760 }
3761 else
3762 {
3763 assert(tc_tabs->type == TERM_CONTAINER_TYPE_SOLO);
3764
3765 /* Create tabs with solo */
3766 assert(term->tab_item == NULL);
3767 _solo_attach(_tab_drag->tabs_child, term->container);
3768 tabs = (Tabs *) term->container->parent;
3769 }
3770
3771 n = eina_list_count(tabs->tabs);
3772 assert (n >= 2);
3773
3774 /* move tab_item to expected place */
3775 if (_tab_drag->previous_position < n)
3776 {
3777 Tab_Item *tab_item = term->tab_item;
3778
3779 tabs->tabs = eina_list_remove(tabs->tabs, tab_item);
3780 if (_tab_drag->previous_position == n-1)
3781 {
3782 tabs->tabs = eina_list_append(tabs->tabs, term->tab_item);
3783 }
3784 else
3785 {
3786 int i = 0;
3787 Eina_List *l;
3788
3789 EINA_LIST_FOREACH(tabs->tabs, l, tab_item)
3790 {
3791 if (i == _tab_drag->previous_position)
3792 {
3793 tabs->tabs = eina_list_prepend_relative_list(tabs->tabs,
3794 term->tab_item,
3795 l);
3796 break;
3797 }
3798 i++;
3799 }
3800 }
3801 }
3802
3803 tc_win->unfocus(tc_win, NULL);
3804 tc->focus(tc, NULL);
3805
3806 /* Repack in correct boxes */
3807 elm_box_unpack_all(term->tabbar.l.box);
3808 elm_box_unpack_all(term->tabbar.r.box);
3809 _tabbar_fill(tabs);
3810
3811 _tab_drag_reparented();
3812 }
3813
3814 static void
_tab_drag_rollback(void)3815 _tab_drag_rollback(void)
3816 {
3817 _focus_validator();
3818 switch (_tab_drag->parent_type)
3819 {
3820 case TERM_CONTAINER_TYPE_TABS:
3821 _tab_drag_rollback_tabs();
3822 break;
3823 case TERM_CONTAINER_TYPE_SPLIT:
3824 _tab_drag_rollback_split();
3825 break;
3826 case TERM_CONTAINER_TYPE_WIN:
3827 _tab_drag_rollback_win();
3828 break;
3829 default:
3830 ERR("invalid parent type:%d", _tab_drag->parent_type);
3831 abort();
3832 }
3833 _focus_validator();
3834 }
3835
3836 static void
_tab_drag_save_state(Term_Container * tc)3837 _tab_drag_save_state(Term_Container *tc)
3838 {
3839 assert(_tab_drag);
3840
3841 _tab_drag->parent_type = tc->parent->type;
3842 switch (_tab_drag->parent_type)
3843 {
3844 case TERM_CONTAINER_TYPE_TABS:
3845 {
3846 int position = 0;
3847 Tabs *tabs;
3848 Eina_List *l;
3849 Tab_Item *tab_item;
3850
3851 tabs = (Tabs*) tc->parent;
3852 EINA_LIST_FOREACH(tabs->tabs, l, tab_item)
3853 {
3854 if (tab_item->tc == tc)
3855 break;
3856 position++;
3857 }
3858 _tab_drag->previous_position = position;
3859 _tab_drag->tabs_child = tc->parent;
3860 }
3861 break;
3862 case TERM_CONTAINER_TYPE_SPLIT:
3863 {
3864 Split *split;
3865
3866 split = (Split*)tc->parent;
3867 _tab_drag->is_horizontal = split->is_horizontal;
3868 if ((_tab_drag->is_first_child = (split->tc1 == tc)))
3869 _tab_drag->other = split->tc2;
3870 else
3871 _tab_drag->other = split->tc1;
3872 _tab_drag->left_size = elm_panes_content_left_size_get(
3873 split->panes);
3874 }
3875 break;
3876 default:
3877 ERR("invalid parent type:%d", tc->parent->type);
3878 abort();
3879 }
3880 }
3881
3882 static void
_tab_drag_free(void)3883 _tab_drag_free(void)
3884 {
3885 if (!_tab_drag)
3886 return;
3887 if (_tab_drag->term_over && _tab_drag->term_over->has_bg_cursor)
3888 {
3889 elm_object_cursor_unset(_tab_drag->term_over->bg);
3890 _tab_drag->term_over->has_bg_cursor = EINA_FALSE;
3891 }
3892 if (_tab_drag->term->has_bg_cursor)
3893 {
3894 elm_object_cursor_unset(_tab_drag->term->bg);
3895 _tab_drag->term->has_bg_cursor = EINA_FALSE;
3896 }
3897
3898 /* free _tab_drag->icon to mark we're freeing _tab_drag */
3899 evas_object_del(_tab_drag->icon);
3900 _tab_drag->icon = NULL;
3901
3902 if (_tab_drag->parent_type != TERM_CONTAINER_TYPE_UNKNOWN)
3903 _tab_drag_rollback();
3904
3905 _tab_drag_disable_anim_over();
3906 for_each_term_do(_tab_drag->term->wn, &_term_hdrag_on, NULL);
3907
3908 ecore_timer_del(_tab_drag->timer);
3909 _tab_drag->timer = NULL;
3910
3911 evas_object_del(_tab_drag->img);
3912 _tab_drag->img = NULL;
3913
3914 term_unref(_tab_drag->term);
3915 free(_tab_drag);
3916 _tab_drag = NULL;
3917 }
3918
3919 static void
_tab_drag_reinsert(Term * term,double mid)3920 _tab_drag_reinsert(Term *term, double mid)
3921 {
3922 Term_Container *tc = term->container;
3923 Term_Container *tc_parent = tc->parent;
3924 Tabs *tabs;
3925
3926 tc = term->container;
3927 assert (tc->type == TERM_CONTAINER_TYPE_SOLO);
3928
3929 if (tc_parent->type != TERM_CONTAINER_TYPE_TABS)
3930 return;
3931
3932 tabs = (Tabs*) tc_parent;
3933
3934 edje_object_part_drag_value_set(term->bg_edj, "terminology.tabl", mid, 0.0);
3935 edje_object_part_drag_value_set(term->bg_edj, "terminology.tabr", mid, 0.0);
3936
3937 _term_on_horizontal_drag(term, NULL, NULL, NULL);
3938 /* In case there is no drag, need to recompute to something valid */
3939 _tabs_recompute_drag(tabs);
3940 }
3941
3942 static void
_tab_reorg(Term * term,Term * to_term,Evas_Coord mx)3943 _tab_reorg(Term *term, Term *to_term, Evas_Coord mx)
3944 {
3945 Term_Container *tc_orig = term->container;
3946 Term_Container *to_tc = to_term->container;
3947
3948 assert(tc_orig->type == TERM_CONTAINER_TYPE_SOLO);
3949 assert(to_tc->type == TERM_CONTAINER_TYPE_SOLO);
3950
3951 if (_tab_drag->split_direction == SPLIT_DIRECTION_TABS)
3952 {
3953 Evas_Coord x = 0, w = 0;
3954 double mid;
3955
3956 edje_object_part_geometry_get(term->bg_edj, "terminology.tabregion",
3957 &x, NULL, &w, NULL);
3958
3959 mid = (double)(mx - x) / (double)w;
3960
3961 _solo_attach(to_tc, tc_orig);
3962
3963 /* reinsert at correct place */
3964 _tab_drag_reparented();
3965 _tab_drag_reinsert(term, mid);
3966 return;
3967 }
3968
3969 to_tc->split_direction(to_tc, to_tc, tc_orig, _tab_drag->split_direction);
3970 _tab_drag_reparented();
3971 }
3972
3973 static void
_tab_drag_stop(void)3974 _tab_drag_stop(void)
3975 {
3976 Evas_Coord mx = 0, my = 0;
3977 Win *wn;
3978 Term_Container *tc_wn;
3979 Term *term;
3980 Term *term_at_coords;
3981
3982 assert(_tab_drag);
3983
3984 term = _tab_drag->term;
3985 wn = term->wn;
3986 tc_wn = (Term_Container*) wn;
3987
3988 evas_pointer_canvas_xy_get(_tab_drag->e, &mx, &my);
3989 term_at_coords = tc_wn->find_term_at_coords(tc_wn, mx, my);
3990 if (!term_at_coords)
3991 goto end;
3992
3993 evas_object_image_source_visible_set(_tab_drag->img, EINA_TRUE);
3994 if (term->has_bg_cursor)
3995 {
3996 elm_object_cursor_unset(term->bg);
3997 term->has_bg_cursor = EINA_FALSE;
3998 }
3999 elm_layout_content_unset(_tab_drag->icon, "terminology.content");
4000 elm_layout_content_set(term->bg, "terminology.content", term->core);
4001 term->unswallowed = EINA_FALSE;
4002 evas_object_show(term->core);
4003 evas_object_show(term->bg);
4004
4005 if (term_at_coords == term)
4006 {
4007 Evas_Coord x = 0, y = 0, w = 0, h = 0, off_x = 0, off_y = 0;
4008 double mid;
4009
4010 /* Reinsert in same set of Tabs or same "tab" (could be a split) */
4011 evas_object_geometry_get(term->bg_edj, &off_x, &off_y, NULL, NULL);
4012 edje_object_part_geometry_get(term->bg_edj, "terminology.tabregion",
4013 &x, &y, &w, &h);
4014 if (!ELM_RECTS_INTERSECT(x,y,w,h, mx,my,1,1))
4015 goto end;
4016
4017 mid = (double)(mx - x) / (double)w;
4018 _tab_drag_reparented();
4019 _tab_drag_reinsert(term, mid);
4020 }
4021 else if (_tab_drag->split_direction != SPLIT_DIRECTION_NONE)
4022 {
4023 /* Move to different set of Tabs */
4024 _tab_reorg(term, term_at_coords, mx);
4025 }
4026
4027 end:
4028 _tab_drag_free();
4029 }
4030
4031 static void
_term_on_drag_stop(void * data,Evas_Object * o EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)4032 _term_on_drag_stop(void *data,
4033 Evas_Object *o EINA_UNUSED,
4034 const char *emission EINA_UNUSED,
4035 const char *source EINA_UNUSED)
4036 {
4037 Term *term = data;
4038 Term_Container *tc;
4039
4040 if (_tab_drag && _tab_drag->icon)
4041 {
4042 _tab_drag_stop();
4043 return;
4044 }
4045 _tab_drag_free();
4046
4047 tc = term->container;
4048 assert (tc->type == TERM_CONTAINER_TYPE_SOLO);
4049
4050 if (tc->parent->type == TERM_CONTAINER_TYPE_TABS)
4051 {
4052 Term_Container *tc_parent = tc->parent;
4053 Tabs *tabs = (Tabs*) tc_parent;
4054
4055 edje_object_part_drag_value_set(term->bg_edj, "terminology.tabl",
4056 tabs->v1_orig, 0.0);
4057 edje_object_part_drag_value_set(term->bg_edj, "terminology.tabr",
4058 tabs->v2_orig, 0.0);
4059 }
4060 _focus_validator();
4061 }
4062
4063
4064 static void
_tabs_drag_mouse_move(void * data EINA_UNUSED,Evas_Object * obj EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)4065 _tabs_drag_mouse_move(
4066 void *data EINA_UNUSED,
4067 Evas_Object *obj EINA_UNUSED,
4068 const char *emission EINA_UNUSED,
4069 const char *source EINA_UNUSED)
4070 {
4071 Evas_Coord x, y, w, h, off_x, off_y, mx, my;
4072 Win *wn;
4073 Term_Container *tc_wn;
4074 Term *term_at_coords;
4075 Split_Direction split_direction = SPLIT_DIRECTION_NONE;
4076
4077 if (!_tab_drag || !_tab_drag->icon)
4078 return;
4079
4080 wn = _tab_drag->term->wn;
4081 tc_wn = (Term_Container*) wn;
4082
4083 evas_object_geometry_get(_tab_drag->icon, NULL, NULL, &w, &h);
4084 evas_pointer_canvas_xy_get(_tab_drag->e, &mx, &my);
4085 x = (mx - (w/2));
4086 y = (my - (h/2));
4087 evas_object_move(_tab_drag->icon, x, y);
4088
4089 term_at_coords = tc_wn->find_term_at_coords(tc_wn, mx, my);
4090 if (!term_at_coords)
4091 return;
4092 evas_object_geometry_get(term_at_coords->bg_edj, &off_x, &off_y, NULL, NULL);
4093
4094 edje_object_part_geometry_get(term_at_coords->bg_edj, "terminology.tabregion",
4095 &x, &y, &w, &h);
4096 if (ELM_RECTS_INTERSECT(x+off_x, y+off_y, w, h, mx, my, 1, 1))
4097 {
4098 split_direction = SPLIT_DIRECTION_TABS;
4099 goto found;
4100 }
4101
4102 edje_object_part_geometry_get(term_at_coords->bg_edj, "drag_left_outline",
4103 &x, &y, &w, &h);
4104 if (ELM_RECTS_INTERSECT(x+off_x, y+off_y, w, h, mx, my, 1, 1))
4105 {
4106 split_direction = SPLIT_DIRECTION_LEFT;
4107 goto found;
4108 }
4109
4110 edje_object_part_geometry_get(term_at_coords->bg_edj, "drag_right_outline",
4111 &x, &y, &w, &h);
4112 if (ELM_RECTS_INTERSECT(x+off_x, y+off_y, w, h, mx, my, 1, 1))
4113 {
4114 split_direction = SPLIT_DIRECTION_RIGHT;
4115 goto found;
4116 }
4117
4118 edje_object_part_geometry_get(term_at_coords->bg_edj, "drag_top_outline",
4119 &x, &y, &w, &h);
4120 if (ELM_RECTS_INTERSECT(x+off_x, y+off_y, w, h, mx, my, 1, 1))
4121 {
4122 split_direction = SPLIT_DIRECTION_TOP;
4123 goto found;
4124 }
4125
4126 edje_object_part_geometry_get(term_at_coords->bg_edj, "drag_bottom_outline",
4127 &x, &y, &w, &h);
4128 if (ELM_RECTS_INTERSECT(x+off_x, y+off_y, w, h, mx, my, 1, 1))
4129 {
4130 split_direction = SPLIT_DIRECTION_BOTTOM;
4131 goto found;
4132 }
4133
4134 found:
4135 if ((_tab_drag->term_over != NULL) &&
4136 ((_tab_drag->term_over != term_at_coords) ||
4137 (_tab_drag->split_direction != split_direction)))
4138 {
4139 _tab_drag_disable_anim_over();
4140 }
4141 if ((split_direction != SPLIT_DIRECTION_NONE) &&
4142 ((_tab_drag->term_over != term_at_coords) ||
4143 (_tab_drag->split_direction != split_direction)))
4144 {
4145 switch (split_direction)
4146 {
4147 case SPLIT_DIRECTION_LEFT:
4148 elm_layout_signal_emit(term_at_coords->bg,
4149 "drag_left,on", "terminology");
4150 break;
4151 case SPLIT_DIRECTION_RIGHT:
4152 elm_layout_signal_emit(term_at_coords->bg,
4153 "drag_right,on", "terminology");
4154 break;
4155 case SPLIT_DIRECTION_TOP:
4156 elm_layout_signal_emit(term_at_coords->bg,
4157 "drag_top,on", "terminology");
4158 break;
4159 case SPLIT_DIRECTION_BOTTOM:
4160 elm_layout_signal_emit(term_at_coords->bg,
4161 "drag_bottom,on", "terminology");
4162 break;
4163 case SPLIT_DIRECTION_TABS:
4164 elm_layout_signal_emit(term_at_coords->bg,
4165 "drag_over_tabs,on", "terminology");
4166 default:
4167 break;
4168 }
4169 }
4170 _tab_drag->term_over = term_at_coords;
4171 _tab_drag->split_direction = split_direction;
4172 }
4173
4174 static Eina_Bool
_tab_drag_start(void * data EINA_UNUSED)4175 _tab_drag_start(void *data EINA_UNUSED)
4176 {
4177 /* Start icons animation before actually drag-starts */
4178 Evas_Coord mx, my, w, h, ch_w, ch_h, core_w, core_h;
4179 Term *term = _tab_drag->term;
4180 Evas_Object *o = elm_layout_add(term->bg);
4181 Evas_Object *img;
4182 Term_Container *tc = term->container;
4183 float ratio;
4184
4185 if (!term->container)
4186 {
4187 _tab_drag_free();
4188 return ECORE_CALLBACK_CANCEL;
4189 }
4190
4191 for_each_term_do(_tab_drag->term->wn, &_term_hdrag_off, NULL);
4192
4193 _tab_drag->icon = o;
4194 theme_apply(o, term->config, "terminology/tab_drag_thumb",
4195 NULL, NULL, EINA_TRUE);
4196 elm_layout_text_set(o, "terminology.title",
4197 term->container->title);
4198 elm_layout_content_unset(term->bg, "terminology.content");
4199 term->unswallowed = EINA_TRUE;
4200 img = evas_object_image_filled_add(evas_object_evas_get(term->core));
4201 evas_object_lower(term->core);
4202 evas_object_move(term->core, -9999, -9999);
4203 evas_object_show(term->core);
4204 evas_object_clip_unset(term->core);
4205 evas_object_image_source_set(img, term->core);
4206 evas_object_geometry_get(term->core, NULL, NULL, &core_w, &core_h);
4207 evas_object_resize(img, core_w, core_h);
4208 _tab_drag->img = img;
4209 elm_layout_content_set(o, "terminology.content", img);
4210 evas_object_size_hint_min_get(term->core, &ch_w, &ch_h);
4211
4212 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
4213 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
4214
4215 w = ch_w * 10;
4216 h = ch_h * 5;
4217 ratio = (float) core_w / (float) core_h;
4218 if (h * ratio > w)
4219 h = w / ratio;
4220 else
4221 w = h * ratio;
4222 evas_object_resize(o, w, h);
4223 evas_pointer_canvas_xy_get(_tab_drag->e, &mx, &my);
4224 evas_object_move(_tab_drag->icon, mx - w/2, my - h/2);
4225 evas_object_raise(o);
4226 elm_object_cursor_set(term->bg, ELM_CURSOR_HAND2);
4227 term->has_bg_cursor = EINA_TRUE;
4228 evas_object_show(o);
4229
4230 _tab_drag_save_state(tc);
4231 DBG("detaching %p from %p", tc, tc->parent);
4232 tc->parent->detach(tc->parent, tc);
4233 assert(term->tab_item == NULL);
4234 _focus_validator();
4235 assert(!tc->is_focused);
4236
4237 _tab_drag->timer = NULL;
4238 return ECORE_CALLBACK_CANCEL;
4239 }
4240
4241 static void
_tabs_mouse_down(void * data,Evas_Object * obj EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)4242 _tabs_mouse_down(
4243 void *data,
4244 Evas_Object *obj EINA_UNUSED,
4245 const char *emission EINA_UNUSED,
4246 const char *source EINA_UNUSED)
4247 {
4248 /* Launch a timer to start drag animation */
4249 Term *term = data;
4250 Evas_Coord mx = 0, my = 0;
4251
4252 assert(term->container != NULL);
4253 assert(_tab_drag == NULL);
4254
4255 _tab_drag = calloc(1, sizeof(*_tab_drag));
4256 if (!_tab_drag)
4257 return;
4258
4259 _tab_drag->e = evas_object_evas_get(term->bg);
4260 evas_pointer_canvas_xy_get(_tab_drag->e, &mx, &my);
4261
4262 term_ref(term);
4263
4264 _tab_drag->mdx = mx;
4265 _tab_drag->mdy = my;
4266 _tab_drag->term = term;
4267 _tab_drag->timer = ecore_timer_add(DRAG_TIMEOUT,
4268 _tab_drag_start, NULL);
4269 }
4270
4271
4272 Eina_Bool
term_tab_go(Term * term,int tnum)4273 term_tab_go(Term *term, int tnum)
4274 {
4275 Term_Container *tc = term->container,
4276 *child = tc;
4277
4278 while (tc)
4279 {
4280 Tabs *tabs;
4281 Tab_Item *tab_item;
4282
4283 if (tc->type != TERM_CONTAINER_TYPE_TABS)
4284 {
4285 child = tc;
4286 tc = tc->parent;
4287 continue;
4288 }
4289 tabs = (Tabs*) tc;
4290 tab_item = eina_list_nth(tabs->tabs, tnum);
4291 if (!tab_item)
4292 {
4293 child = tc;
4294 tc = tc->parent;
4295 continue;
4296 }
4297 if (tab_item != tabs->current)
4298 tab_item->tc->focus(tab_item->tc, child);
4299 return EINA_TRUE;
4300 }
4301 return EINA_FALSE;
4302 }
4303
4304 static void
4305 _tabs_selector_cb_selected(void *data,
4306 Evas_Object *_obj EINA_UNUSED,
4307 void *info);
4308 static void
4309 _tabs_selector_cb_exit(void *data,
4310 Evas_Object *_obj EINA_UNUSED,
4311 void *_info EINA_UNUSED);
4312
4313 static void
4314 _tabs_selector_cb_ending(void *data,
4315 Evas_Object *_obj EINA_UNUSED,
4316 void *_info EINA_UNUSED);
4317
4318 static void
_tabs_restore(Tabs * tabs)4319 _tabs_restore(Tabs *tabs)
4320 {
4321 Eina_List *l;
4322 Tab_Item *tab_item;
4323 Term_Container *tc = (Term_Container*)tabs;
4324 Term *term;
4325 Solo *solo;
4326 Win *wn = tc->wn;
4327 Evas_Object *selector = tabs->selector;
4328 Evas_Object *selector_bg = tabs->selector_bg;
4329
4330 if (!tabs->selector)
4331 return;
4332
4333 EINA_LIST_FOREACH(wn->terms, l, term)
4334 {
4335 if (term->unswallowed)
4336 {
4337 evas_object_image_source_visible_set(term->sel, EINA_TRUE);
4338 elm_layout_content_set(term->bg, "terminology.content", term->core);
4339 term->unswallowed = EINA_FALSE;
4340 evas_object_show(term->core);
4341 }
4342 }
4343
4344 EINA_LIST_FOREACH(tabs->tabs, l, tab_item)
4345 {
4346 tab_item->selector_entry = NULL;
4347 if (tab_item->tc->is_focused)
4348 tab_item->tc->unfocus(tab_item->tc, tc);
4349 }
4350
4351 evas_object_smart_callback_del_full(selector, "selected",
4352 _tabs_selector_cb_selected, tabs);
4353 evas_object_smart_callback_del_full(selector, "exit",
4354 _tabs_selector_cb_exit, tabs);
4355 evas_object_smart_callback_del_full(selector, "ending",
4356 _tabs_selector_cb_ending, tabs);
4357
4358
4359 tabs->selector = NULL;
4360 tabs->selector_bg = NULL;
4361
4362 /* XXX: reswallow in parent */
4363 tc->parent->swallow(tc->parent, tc, tc);
4364 solo = (Solo*)tabs->current->tc;
4365 term = solo->term;
4366 _tabbar_clear(term);
4367
4368 /* Restore -> recreate the whole tabbar */
4369 _tabs_recreate(tabs);
4370 tabs->current->tc->unfocus(tabs->current->tc, tabs->current->tc);
4371 tabs->current->tc->focus(tabs->current->tc, tabs->current->tc);
4372
4373 elm_object_focus_set(selector, EINA_FALSE);
4374
4375 evas_object_del(selector);
4376 evas_object_del(selector_bg);
4377 }
4378
4379 static void
_tabs_selector_cb_ending(void * data,Evas_Object * _obj EINA_UNUSED,void * _info EINA_UNUSED)4380 _tabs_selector_cb_ending(void *data,
4381 Evas_Object *_obj EINA_UNUSED,
4382 void *_info EINA_UNUSED)
4383 {
4384 Tabs *tabs = data;
4385
4386 edje_object_signal_emit(tabs->selector_bg, "end", "terminology");
4387 }
4388
4389 static void
_tabs_selector_cb_selected(void * data,Evas_Object * _obj EINA_UNUSED,void * info)4390 _tabs_selector_cb_selected(void *data,
4391 Evas_Object *_obj EINA_UNUSED,
4392 void *info)
4393 {
4394 Tabs *tabs = data;
4395 Eina_List *l;
4396 Tab_Item *tab_item;
4397
4398 EINA_LIST_FOREACH(tabs->tabs, l, tab_item)
4399 {
4400 if (tab_item->tc->selector_img == info)
4401 {
4402 tabs->current = tab_item;
4403 _tabs_restore(tabs);
4404 return;
4405 }
4406 }
4407
4408 ERR("Can't find selected tab item");
4409 }
4410
4411 static void
_tabs_selector_cb_exit(void * data,Evas_Object * _obj EINA_UNUSED,void * _info EINA_UNUSED)4412 _tabs_selector_cb_exit(void *data,
4413 Evas_Object *_obj EINA_UNUSED,
4414 void *_info EINA_UNUSED)
4415 {
4416 Tabs *tabs = data;
4417
4418 _tabs_restore(tabs);
4419 }
4420
4421 static void
_cb_tab_selector_show(Tabs * tabs,Tab_Item * to_item)4422 _cb_tab_selector_show(Tabs *tabs, Tab_Item *to_item)
4423 {
4424 Term_Container *tc = (Term_Container *)tabs;
4425 Eina_List *l;
4426 int count;
4427 double z;
4428 Win *wn = tc->wn;
4429 Tab_Item *tab_item;
4430 Evas_Object *o;
4431 Evas_Coord x, y, w, h;
4432 Edje_Message_Int msg;
4433
4434 if (tabs->selector_bg)
4435 return;
4436
4437 o = tc->get_evas_object(tc);
4438 evas_object_geometry_get(o, &x, &y, &w, &h);
4439
4440 tabs->selector_bg = edje_object_add(evas_object_evas_get(tc->wn->win));
4441 theme_apply(tabs->selector_bg, wn->config, "terminology/sel/base",
4442 NULL, NULL, EINA_FALSE);
4443
4444 evas_object_geometry_set(tabs->selector_bg, x, y, w, h);
4445 evas_object_hide(o);
4446
4447 if (wn->config->translucent)
4448 msg.val = wn->config->opacity;
4449 else
4450 msg.val = 100;
4451 edje_object_message_send(tabs->selector_bg, EDJE_MESSAGE_INT, 1, &msg);
4452 background_set_shine(wn->config, tabs->selector_bg);
4453 edje_object_signal_emit(tabs->selector_bg, "begin", "terminology");
4454
4455 tabs->selector = sel_add(wn->win);
4456 EINA_LIST_FOREACH(tabs->tabs, l, tab_item)
4457 {
4458 Evas_Object *img;
4459 Eina_Bool is_selected, missed_bell;
4460 Solo *solo;
4461 Term *term;
4462
4463 solo = (Solo*)tab_item->tc;
4464 term = solo->term;
4465 _tabbar_clear(term);
4466
4467 elm_layout_content_unset(term->bg, "terminology.content");
4468 term->unswallowed = EINA_TRUE;
4469 img = evas_object_image_filled_add(evas_object_evas_get(wn->win));
4470 o = term->core;
4471 evas_object_lower(o);
4472 evas_object_move(o, -9999, -9999);
4473 evas_object_show(o);
4474 evas_object_clip_unset(o);
4475 evas_object_image_source_set(img, o);
4476 evas_object_geometry_get(o, NULL, NULL, &w, &h);
4477 evas_object_resize(img, w, h);
4478 evas_object_data_set(img, "tc", tab_item->tc);
4479 tab_item->tc->selector_img = img;
4480
4481 is_selected = (tab_item == tabs->current);
4482 missed_bell = term->missed_bell;
4483 tab_item->selector_entry = NULL;
4484 tab_item->selector_entry = sel_entry_add(tabs->selector, img,
4485 is_selected,
4486 missed_bell, wn->config);
4487 }
4488 edje_object_part_swallow(tabs->selector_bg, "terminology.content",
4489 tabs->selector);
4490
4491 evas_object_show(tabs->selector);
4492
4493 /* XXX: refresh */
4494 tc->parent->swallow(tc->parent, tc, tc);
4495
4496 evas_object_show(tabs->selector_bg);
4497 evas_object_smart_callback_add(tabs->selector, "selected",
4498 _tabs_selector_cb_selected, tabs);
4499 evas_object_smart_callback_add(tabs->selector, "exit",
4500 _tabs_selector_cb_exit, tabs);
4501 evas_object_smart_callback_add(tabs->selector, "ending",
4502 _tabs_selector_cb_ending, tabs);
4503 z = 1.0;
4504 sel_go(tabs->selector);
4505 count = eina_list_count(tabs->tabs);
4506 if (count >= 1)
4507 z = 1.0 / (sqrt(count) * 0.8);
4508 if (z > 1.0) z = 1.0;
4509 sel_orig_zoom_set(tabs->selector, z);
4510 sel_zoom(tabs->selector, z);
4511 if (to_item)
4512 {
4513 sel_entry_selected_set(tabs->selector, to_item->tc->selector_img,
4514 EINA_TRUE);
4515 sel_exit(tabs->selector);
4516 }
4517 }
4518
4519 static void
_cb_select(void * data,Evas_Object * _obj EINA_UNUSED,void * _event EINA_UNUSED)4520 _cb_select(void *data,
4521 Evas_Object *_obj EINA_UNUSED,
4522 void *_event EINA_UNUSED)
4523 {
4524 Term *term = data;
4525 Term_Container *tc = term->container;
4526
4527 while (tc)
4528 {
4529 Tabs *tabs;
4530
4531 if (tc->type != TERM_CONTAINER_TYPE_TABS)
4532 {
4533 tc = tc->parent;
4534 continue;
4535 }
4536 tabs = (Tabs*) tc;
4537 if (eina_list_count(tabs->tabs) < 2)
4538 {
4539 tc = tc->parent;
4540 continue;
4541 }
4542
4543 _cb_tab_selector_show(tabs, NULL);
4544 return;
4545 }
4546 }
4547
4548
4549
4550 static Evas_Object *
_tabs_get_evas_object(const Term_Container * container)4551 _tabs_get_evas_object(const Term_Container *container)
4552 {
4553 Tabs *tabs;
4554 Term_Container *tc;
4555
4556 assert (container->type == TERM_CONTAINER_TYPE_TABS);
4557 tabs = (Tabs*)container;
4558
4559 if (tabs->selector_bg)
4560 return tabs->selector_bg;
4561
4562 assert(tabs->current != NULL);
4563 tc = tabs->current->tc;
4564 return tc->get_evas_object(tc);
4565 }
4566
4567 static Term *
_tabs_focused_term_get(const Term_Container * tc)4568 _tabs_focused_term_get(const Term_Container *tc)
4569 {
4570 Tabs *tabs;
4571
4572 assert (tc->type == TERM_CONTAINER_TYPE_TABS);
4573 tabs = (Tabs*)tc;
4574
4575 return tc->is_focused ?
4576 tabs->current->tc->focused_term_get(tabs->current->tc)
4577 : NULL;
4578 }
4579
4580 static Term *
_tabs_find_term_at_coords(const Term_Container * container,Evas_Coord mx,Evas_Coord my)4581 _tabs_find_term_at_coords(const Term_Container *container,
4582 Evas_Coord mx,
4583 Evas_Coord my)
4584 {
4585 Tabs *tabs;
4586 Term_Container *tc;
4587
4588 assert (container->type == TERM_CONTAINER_TYPE_TABS);
4589 tabs = (Tabs*)container;
4590
4591 tc = tabs->current->tc;
4592
4593 return tc->find_term_at_coords(tc, mx, my);
4594 }
4595
4596 static void
_tabs_size_eval(Term_Container * container,Sizeinfo * info)4597 _tabs_size_eval(Term_Container *container, Sizeinfo *info)
4598 {
4599 Tabs *tabs;
4600 Term_Container *tc;
4601 Config *config;
4602
4603 assert (container->type == TERM_CONTAINER_TYPE_TABS);
4604 tabs = (Tabs*)container;
4605
4606 tc = tabs->current->tc;
4607 config = tc->wn->config;
4608 tc->size_eval(tc, info);
4609 /* Current sizing code does not take the tab area correctly into account */
4610 if (config->show_tabs)
4611 {
4612 info->step_x = 1;
4613 info->step_y = 1;
4614 }
4615 }
4616
4617 static Eina_List *
_tab_item_find(const Tabs * tabs,const Term_Container * child,int * pos)4618 _tab_item_find(const Tabs *tabs, const Term_Container *child,
4619 int *pos)
4620 {
4621 Eina_List *l;
4622 Tab_Item *tab_item;
4623 int i = 0;
4624
4625 EINA_LIST_FOREACH(tabs->tabs, l, tab_item)
4626 {
4627 if (tab_item->tc == child)
4628 {
4629 if (pos)
4630 *pos = i;
4631 return l;
4632 }
4633 i++;
4634 }
4635 return NULL;
4636 }
4637
4638 static void
_tabs_close(Term_Container * tc,Term_Container * child)4639 _tabs_close(Term_Container *tc, Term_Container *child)
4640 {
4641 int count;
4642 Tabs *tabs;
4643 Eina_List *l;
4644 Tab_Item *item, *next_item;
4645 Eina_List *next;
4646 Term_Container *next_child, *tc_parent;
4647 Term *term;
4648 Solo *solo;
4649 int pos = 0;
4650
4651 /* TODO: figure out whether to move position if tab_drag */
4652
4653 assert (tc->type == TERM_CONTAINER_TYPE_TABS);
4654 tabs = (Tabs*)tc;
4655
4656 tc_parent = tc->parent;
4657
4658 l = _tab_item_find(tabs, child, &pos);
4659 item = l->data;
4660
4661 next = eina_list_next(l);
4662 if (!next)
4663 next = tabs->tabs;
4664
4665 tabs->tabs = eina_list_remove_list(tabs->tabs, l);
4666
4667 next_item = next->data;
4668 next_child = next_item->tc;
4669 assert (next_child->type == TERM_CONTAINER_TYPE_SOLO);
4670
4671 assert (child->type == TERM_CONTAINER_TYPE_SOLO);
4672 solo = (Solo*)child;
4673 term = solo->term;
4674 child->unfocus(child, tc);
4675
4676 elm_layout_signal_emit(term->bg, "tabcount,off", "terminology");
4677 elm_layout_signal_emit(term->bg, "tab_btn,off", "terminology");
4678
4679 count = eina_list_count(tabs->tabs);
4680 if (count == 1)
4681 {
4682 Term *next_term;
4683 Solo *next_solo;
4684 Config *config;
4685
4686 assert (next_child->type == TERM_CONTAINER_TYPE_SOLO);
4687 next_solo = (Solo*)next_child;
4688 next_term = next_solo->term;
4689 assert(next_term != term);
4690 assert(tc != next_child);
4691 config = next_term->config;
4692
4693 _tabbar_clear(term);
4694
4695 evas_object_del(next_term->tab_spacer);
4696 next_term->tab_spacer = NULL;
4697 if (next_term->tab_inactive)
4698 {
4699 evas_object_hide(next_term->tab_inactive);
4700 edje_object_signal_callback_del(next_term->tab_inactive,
4701 "tab,activate", "terminology",
4702 _cb_tab_activate);
4703 }
4704 elm_layout_signal_emit(next_term->bg, "tabcount,off", "terminology");
4705 elm_layout_signal_emit(next_term->bg, "tab_btn,off", "terminology");
4706
4707 if (tabs->selector)
4708 _tabs_restore(tabs);
4709
4710 if (config->show_tabs)
4711 _solo_tab_show(next_child);
4712
4713 eina_stringshare_del(tc->title);
4714
4715 tc_parent->swallow(tc_parent, tc, next_child);
4716 if (tc->is_focused)
4717 next_child->focus(next_child, tc);
4718
4719 if ((_tab_drag) && (_tab_drag->parent_type == TERM_CONTAINER_TYPE_TABS)
4720 && (_tab_drag->tabs_child == tc))
4721 {
4722 _tab_drag->tabs_child = next_child;
4723 _solo_tab_show(next_child);
4724 }
4725
4726 _tab_item_free(item);
4727 _tab_item_free(next_item);
4728 EINA_LIST_FREE(tabs->tabs, item) {}
4729 free(tc);
4730
4731 return;
4732 }
4733
4734 if ((_tab_drag) && (_tab_drag->parent_type == TERM_CONTAINER_TYPE_TABS)
4735 && (_tab_drag->tabs_child == tc))
4736 {
4737 if (pos < _tab_drag->previous_position)
4738 _tab_drag->previous_position--;
4739 }
4740
4741 if (item->tc->selector_img)
4742 {
4743 Evas_Object *o;
4744 o = item->tc->selector_img;
4745 item->tc->selector_img = NULL;
4746 evas_object_del(o);
4747 }
4748
4749 count--;
4750
4751 if (item == tabs->current)
4752 {
4753 tc->swallow(tc, child, next_child);
4754 if (tc->is_focused)
4755 next_child->focus(next_child, tc);
4756 _tab_item_free(item);
4757 assert(tabs->current != item);
4758 return;
4759 }
4760 _tab_item_free(item);
4761
4762 _tabs_recompute_drag(tabs);
4763 }
4764
4765 static void
_tabs_update(Term_Container * tc)4766 _tabs_update(Term_Container *tc)
4767 {
4768 Tabs *tabs;
4769 assert (tc->type == TERM_CONTAINER_TYPE_TABS);
4770 tabs = (Tabs*)tc;
4771
4772 /* Update -> recreate the whole tabbar */
4773 _tabs_recreate(tabs);
4774 }
4775
4776 static Term *
_tabs_term_next(const Term_Container * tc,const Term_Container * child)4777 _tabs_term_next(const Term_Container *tc, const Term_Container *child)
4778 {
4779 Tabs *tabs;
4780 Tab_Item *tab_item;
4781 Eina_List *l;
4782
4783 assert (tc->type == TERM_CONTAINER_TYPE_TABS);
4784 tabs = (Tabs*)tc;
4785 l = _tab_item_find(tabs, child, NULL);
4786 l = eina_list_next(l);
4787 if (l)
4788 {
4789 tab_item = l->data;
4790 tc = tab_item->tc;
4791 return tc->term_first(tc);
4792 }
4793 else
4794 {
4795 return tc->parent->term_next(tc->parent, tc);
4796 }
4797 }
4798
4799 static Term *
_tabs_term_prev(const Term_Container * tc,const Term_Container * child)4800 _tabs_term_prev(const Term_Container *tc, const Term_Container *child)
4801 {
4802 Tabs *tabs;
4803 Tab_Item *tab_item;
4804 Eina_List *l;
4805
4806 assert (tc->type == TERM_CONTAINER_TYPE_TABS);
4807 tabs = (Tabs*)tc;
4808 l = _tab_item_find(tabs, child, NULL);
4809 l = eina_list_prev(l);
4810 if (l)
4811 {
4812 tab_item = l->data;
4813 tc = tab_item->tc;
4814 return tc->term_last(tc);
4815 }
4816 else
4817 {
4818 return tc->parent->term_prev(tc->parent, tc);
4819 }
4820 }
4821
4822 static Term *
_tabs_term_up(const Term_Container * tc,const Term_Container * _child EINA_UNUSED)4823 _tabs_term_up(const Term_Container *tc,
4824 const Term_Container *_child EINA_UNUSED)
4825 {
4826 return tc->parent->term_up(tc->parent, tc);
4827 }
4828
4829 static Term *
_tabs_term_down(const Term_Container * tc,const Term_Container * _child EINA_UNUSED)4830 _tabs_term_down(const Term_Container *tc,
4831 const Term_Container *_child EINA_UNUSED)
4832 {
4833 return tc->parent->term_down(tc->parent, tc);
4834 }
4835
4836 static Term *
_tabs_term_left(const Term_Container * tc,const Term_Container * _child EINA_UNUSED)4837 _tabs_term_left(const Term_Container *tc,
4838 const Term_Container *_child EINA_UNUSED)
4839 {
4840 return tc->parent->term_left(tc->parent, tc);
4841 }
4842
4843 static Term *
_tabs_term_right(const Term_Container * tc,const Term_Container * _child EINA_UNUSED)4844 _tabs_term_right(const Term_Container *tc,
4845 const Term_Container *_child EINA_UNUSED)
4846 {
4847 return tc->parent->term_right(tc->parent, tc);
4848 }
4849
4850 static Term *
_tabs_term_first(const Term_Container * tc)4851 _tabs_term_first(const Term_Container *tc)
4852 {
4853 Tabs *tabs;
4854 Tab_Item *tab_item;
4855
4856 assert (tc->type == TERM_CONTAINER_TYPE_TABS);
4857 tabs = (Tabs*)tc;
4858
4859 tab_item = tabs->tabs->data;
4860 tc = tab_item->tc;
4861
4862 return tc->term_first(tc);
4863 }
4864
4865 static Term *
_tabs_term_last(const Term_Container * tc)4866 _tabs_term_last(const Term_Container *tc)
4867 {
4868 Tabs *tabs;
4869 Tab_Item *tab_item;
4870 Eina_List *l;
4871
4872 assert (tc->type == TERM_CONTAINER_TYPE_TABS);
4873 tabs = (Tabs*)tc;
4874
4875 l = eina_list_last(tabs->tabs);
4876 tab_item = l->data;
4877 tc = tab_item->tc;
4878
4879 return tc->term_last(tc);
4880 }
4881
4882 static void
_tabcount_refresh(Tabs * tabs)4883 _tabcount_refresh(Tabs *tabs)
4884 {
4885 Eina_List *l;
4886 Tab_Item *tab_item;
4887 Term *main_term = _tab_item_to_term(tabs->current);
4888 Evas *canvas = evas_object_evas_get(main_term->bg);
4889 char buf[32], bufmissed[32];
4890 int n = eina_list_count(tabs->tabs);
4891 Evas_Coord w = 0, h = 0;
4892 unsigned int missed = 0;
4893 int i;
4894
4895 if (n <= 0)
4896 {
4897 ERR("no tab");
4898 return;
4899 }
4900
4901 buf[0] = '\0';
4902 i = 0;
4903 EINA_LIST_FOREACH(tabs->tabs, l, tab_item)
4904 {
4905 Solo *solo;
4906 Term *term;
4907
4908 i++;
4909 assert (tab_item->tc->type == TERM_CONTAINER_TYPE_SOLO);
4910 solo = (Solo*) tab_item->tc;
4911 term = solo->term;
4912
4913 if (term->tab_inactive)
4914 {
4915 evas_object_hide(term->tab_inactive);
4916 edje_object_signal_callback_del(term->tab_inactive,
4917 "tab,activate", "terminology",
4918 _cb_tab_activate);
4919 }
4920
4921 if (tabs->current == tab_item)
4922 {
4923 snprintf(buf, sizeof(buf), "%i/%i", i, n);
4924 }
4925 else if (term->missed_bell)
4926 missed++;
4927 }
4928 if (missed > 0)
4929 snprintf(bufmissed, sizeof(bufmissed), "%i", missed);
4930 else
4931 bufmissed[0] = '\0';
4932
4933 if (!main_term->tab_spacer)
4934 {
4935 main_term->tab_spacer = evas_object_rectangle_add(canvas);
4936 evas_object_color_set(main_term->tab_spacer, 0, 0, 0, 0);
4937 }
4938 elm_coords_finger_size_adjust(1, &w, 1, &h);
4939 evas_object_size_hint_min_set(main_term->tab_spacer, w, h);
4940
4941 elm_layout_content_set(main_term->bg, "terminology.tabcount.control",
4942 main_term->tab_spacer);
4943 elm_layout_text_set(main_term->bg, "terminology.tabcount.label", buf);
4944 elm_layout_text_set(main_term->bg, "terminology.tabmissed.label", bufmissed);
4945 elm_layout_signal_emit(main_term->bg, "tabcount,on", "terminology");
4946 _tabbar_clear(main_term);
4947 if (missed > 0)
4948 elm_layout_signal_emit(main_term->bg, "tabmissed,on", "terminology");
4949 else
4950 elm_layout_signal_emit(main_term->bg, "tabmissed,off", "terminology");
4951 }
4952
4953 static void
_tabs_swallow(Term_Container * tc,Term_Container * orig,Term_Container * new_child)4954 _tabs_swallow(Term_Container *tc, Term_Container *orig,
4955 Term_Container *new_child)
4956 {
4957 Tabs *tabs;
4958 Tab_Item *tab_item;
4959 Eina_List *l;
4960 Evas_Object *o;
4961 Evas_Coord x, y, w, h;
4962 Term *term_orig, *term_new;
4963 Solo *solo_orig, *solo_new;
4964 Term_Container *tc_parent = tc->parent;
4965
4966 assert (tc->type == TERM_CONTAINER_TYPE_TABS);
4967 tabs = (Tabs*) tc;
4968
4969 l = _tab_item_find(tabs, new_child, NULL);
4970 tab_item = l->data;
4971
4972 if (tabs->selector)
4973 {
4974 Evas_Object *img = tab_item->tc->selector_img;
4975 evas_object_image_source_set(img,
4976 new_child->get_evas_object(new_child));
4977 evas_object_data_set(img, "tc", new_child);
4978 if (tab_item->selector_entry)
4979 sel_entry_update(tab_item->selector_entry);
4980 return;
4981 }
4982 if (orig == new_child)
4983 {
4984 assert(tabs->current == tab_item);
4985 return;
4986 }
4987
4988 /* Occurs when closing current tab */
4989 if (tc->is_focused)
4990 tabs->current->tc->unfocus(tabs->current->tc, tc);
4991
4992 assert (orig->type == TERM_CONTAINER_TYPE_SOLO);
4993 solo_orig = (Solo*)orig;
4994 term_orig = solo_orig->term;
4995 assert (new_child->type == TERM_CONTAINER_TYPE_SOLO);
4996 solo_new = (Solo*)new_child;
4997 term_new = solo_new->term;
4998
4999 tabs->current = tab_item;
5000 /* Remove tab effects from the previous focused tab */
5001 elm_layout_signal_emit(term_orig->bg, "tabcount,off", "terminology");
5002
5003 if (term_new->config->show_tabs)
5004 {
5005 _tabs_get_or_create_boxes(term_new, term_orig);
5006 assert(term_new == _tab_item_to_term(tabs->current));
5007 _tabbar_fill(tabs);
5008 }
5009 else
5010 {
5011 _tabcount_refresh(tabs);
5012 }
5013
5014 o = orig->get_evas_object(orig);
5015 evas_object_geometry_get(o, &x, &y, &w, &h);
5016 evas_object_hide(o);
5017 o = new_child->get_evas_object(new_child);
5018 evas_object_geometry_set(o, x, y, w, h);
5019 evas_object_show(o);
5020 /* XXX: need to refresh */
5021 tc_parent->swallow(tc_parent, tc, tc);
5022 }
5023
5024
5025 static void
_tab_new_cb(void * data,Evas_Object * _obj EINA_UNUSED,void * _event_info EINA_UNUSED)5026 _tab_new_cb(void *data,
5027 Evas_Object *_obj EINA_UNUSED,
5028 void *_event_info EINA_UNUSED)
5029 {
5030 Tabs *tabs = data;
5031 Term_Container *tc = (Term_Container*) tabs,
5032 *tc_new;
5033 Term *tm_new;
5034 Win *wn = tc->wn;
5035 char *wdir = NULL;
5036 char buf[PATH_MAX];
5037
5038 // copy the current path to wdir if we should change the directory,
5039 // passing wdir NULL otherwise:
5040 if (wn->config->changedir_to_current)
5041 {
5042 Term *tm;
5043 Term_Container *tc_old = tabs->current->tc;
5044 tm = tc_old->term_first(tc_old);
5045
5046 if (tm && termio_cwd_get(tm->termio, buf, sizeof(buf)))
5047 wdir = buf;
5048 }
5049
5050 tm_new = term_new(wn, wn->config,
5051 NULL, wn->config->login_shell, wdir,
5052 80, 24, EINA_FALSE, NULL);
5053 tc_new = _solo_new(tm_new, wn);
5054 evas_object_data_set(tm_new->termio, "sizedone", tm_new->termio);
5055
5056 _tabs_attach(tc, tc_new);
5057 }
5058
5059 static void
_cb_new(void * data,Evas_Object * _obj EINA_UNUSED,void * _event EINA_UNUSED)5060 _cb_new(void *data,
5061 Evas_Object *_obj EINA_UNUSED,
5062 void *_event EINA_UNUSED)
5063 {
5064 Term *term = data;
5065 Term_Container *tc = term->container;
5066
5067 assert (tc->type == TERM_CONTAINER_TYPE_SOLO);
5068
5069 _solo_tabs_new(tc);
5070 _focus_validator();
5071 }
5072
5073 static void
_cb_close(void * data,Evas_Object * _obj EINA_UNUSED,void * _event EINA_UNUSED)5074 _cb_close(void *data,
5075 Evas_Object *_obj EINA_UNUSED,
5076 void *_event EINA_UNUSED)
5077 {
5078 Term *term = data;
5079 Term_Container *tc = term->container;
5080
5081 term_close(tc->wn->win, term->termio, EINA_FALSE);
5082 }
5083
5084 void
main_new(Evas_Object * term)5085 main_new(Evas_Object *term)
5086 {
5087 Term *tm;
5088
5089 tm = evas_object_data_get(term, "term");
5090 if (!tm) return;
5091
5092 _cb_new(tm, term, NULL);
5093 }
5094
5095 static void
_tabs_focus(Term_Container * tc,Term_Container * relative)5096 _tabs_focus(Term_Container *tc, Term_Container *relative)
5097 {
5098 Tabs *tabs;
5099
5100 assert (tc->type == TERM_CONTAINER_TYPE_TABS);
5101 tabs = (Tabs*) tc;
5102
5103 if (!tc->parent)
5104 return;
5105
5106 DBG("tc:%p tc->is_focused:%d from_parent:%d",
5107 tc, tc->is_focused, tc->parent == relative);
5108 if (tc->parent == relative)
5109 {
5110 if (!tc->is_focused)
5111 {
5112 tc->is_focused = EINA_TRUE;
5113 tabs->current->tc->focus(tabs->current->tc, tc);
5114 }
5115 }
5116 else
5117 {
5118 Eina_List *l;
5119 Tab_Item *tab_item;
5120
5121 l = _tab_item_find(tabs, relative, NULL);
5122 if (!l)
5123 return;
5124
5125 tc->is_focused = EINA_TRUE;
5126
5127 tab_item = l->data;
5128 if (tab_item != tabs->current)
5129 {
5130 Config *config = tc->wn->config;
5131 tabs->current->tc->unfocus(tabs->current->tc, tc);
5132
5133 if (config->tab_zoom >= 0.01 && !config->show_tabs)
5134 {
5135 _cb_tab_selector_show(tabs, tab_item);
5136 return;
5137 }
5138
5139 tc->swallow(tc, tabs->current->tc, relative);
5140 }
5141 tc->parent->focus(tc->parent, tc);
5142 }
5143 }
5144
5145 static void
_tabs_unfocus(Term_Container * tc,Term_Container * relative)5146 _tabs_unfocus(Term_Container *tc, Term_Container *relative)
5147 {
5148 Tabs *tabs;
5149
5150 DBG("tc:%p tc->is_focused:%d from_parent:%d",
5151 tc, tc->is_focused, tc->parent == relative);
5152 if (!tc->is_focused)
5153 return;
5154 if (!tc->parent)
5155 return;
5156
5157 assert (tc->type == TERM_CONTAINER_TYPE_TABS);
5158 tabs = (Tabs*) tc;
5159
5160 if (tc->parent == relative)
5161 {
5162 tabs->current->tc->unfocus(tabs->current->tc, tc);
5163 tc->is_focused = EINA_FALSE;
5164 }
5165 else
5166 {
5167 Tab_Item *tab_item;
5168 Eina_List *l;
5169
5170 EINA_LIST_FOREACH(tabs->tabs, l, tab_item)
5171 {
5172 if (relative == tab_item->tc) {
5173 tc->parent->unfocus(tc->parent, tc);
5174 tc->is_focused = EINA_FALSE;
5175 return;
5176 }
5177 }
5178 }
5179 }
5180
5181 static void
_tabs_bell(Term_Container * tc,Term_Container * child)5182 _tabs_bell(Term_Container *tc,
5183 Term_Container *child)
5184 {
5185 Tabs *tabs;
5186 Term *term;
5187 Solo *solo;
5188 char bufmissed[32];
5189 Eina_List *l;
5190 Tab_Item *tab_item;
5191 int missed = 0;
5192
5193 assert (tc->type == TERM_CONTAINER_TYPE_TABS);
5194 tabs = (Tabs*) tc;
5195
5196 assert (child->type == TERM_CONTAINER_TYPE_SOLO);
5197 solo = (Solo*)child;
5198 term = solo->term;
5199
5200 if (tc->is_focused && child->is_focused)
5201 return;
5202
5203 if (term->tab_inactive && term->missed_bell)
5204 edje_object_signal_emit(term->tab_inactive, "bell", "terminology");
5205
5206 EINA_LIST_FOREACH(tabs->tabs, l, tab_item)
5207 {
5208 assert (tab_item->tc->type == TERM_CONTAINER_TYPE_SOLO);
5209 solo = (Solo*) tab_item->tc;
5210 term = solo->term;
5211
5212 if (term->missed_bell)
5213 missed++;
5214 }
5215
5216 tab_item = tabs->current;
5217 assert (tab_item->tc->type == TERM_CONTAINER_TYPE_SOLO);
5218 solo = (Solo*)tab_item->tc;
5219 term = solo->term;
5220 if (missed > 0)
5221 {
5222 snprintf(bufmissed, sizeof(bufmissed), "%i", missed);
5223 elm_layout_text_set(term->bg, "terminology.tabmissed.label", bufmissed);
5224 elm_layout_signal_emit(term->bg, "tabmissed,on", "terminology");
5225 }
5226 else
5227 elm_layout_signal_emit(term->bg, "tabmissed,off", "terminology");
5228 edje_object_message_signal_process(term->bg_edj);
5229
5230 tc->parent->bell(tc->parent, tc);
5231 }
5232
5233 static void
_tabs_set_title(Term_Container * tc,Term_Container * child,const char * title)5234 _tabs_set_title(Term_Container *tc, Term_Container *child,
5235 const char *title)
5236 {
5237 Tabs *tabs;
5238 Tab_Item *tab_item;
5239 Eina_List *l;
5240 Solo *solo;
5241 Term *term;
5242
5243 assert (tc->type == TERM_CONTAINER_TYPE_TABS);
5244 tabs = (Tabs*) tc;
5245
5246 l = _tab_item_find(tabs, child, NULL);
5247 if (!l)
5248 return;
5249 tab_item = l->data;
5250
5251 if (tabs->selector && tab_item->selector_entry)
5252 {
5253 sel_entry_title_set(tab_item->selector_entry, title);
5254 }
5255
5256 assert (tab_item->tc->type == TERM_CONTAINER_TYPE_SOLO);
5257 solo = (Solo*)tab_item->tc;
5258 term = solo->term;
5259
5260 if (tab_item == tabs->current)
5261 {
5262 eina_stringshare_del(tc->title);
5263 tc->title = eina_stringshare_ref(title);
5264 tc->parent->set_title(tc->parent, tc, title);
5265
5266 if (term->config->show_tabs)
5267 {
5268 elm_layout_text_set(term->bg, "terminology.tab.title", title);
5269 }
5270 }
5271 else
5272 {
5273 if (term->tab_inactive)
5274 edje_object_part_text_set(term->tab_inactive,
5275 "terminology.title",
5276 title);
5277 }
5278 }
5279
5280 static void
_tabs_recreate(Tabs * tabs)5281 _tabs_recreate(Tabs *tabs)
5282 {
5283 Eina_List *l;
5284 Solo *solo;
5285 Term *term;
5286 Tab_Item *tab_item;
5287 Evas_Coord w = 0, h = 0;
5288 int missed = 0;
5289 int n = eina_list_count(tabs->tabs);
5290
5291 if (n <= 0)
5292 {
5293 ERR("no tab");
5294 return;
5295 }
5296
5297 EINA_LIST_FOREACH(tabs->tabs, l, tab_item)
5298 {
5299 assert (tab_item->tc->type == TERM_CONTAINER_TYPE_SOLO);
5300 solo = (Solo*) tab_item->tc;
5301 term = solo->term;
5302
5303 if (term->tab_inactive)
5304 {
5305 evas_object_hide(term->tab_inactive);
5306 edje_object_signal_callback_del(term->tab_inactive,
5307 "tab,activate", "terminology",
5308 _cb_tab_activate);
5309 }
5310
5311 if (term->missed_bell)
5312 missed++;
5313 }
5314
5315 tab_item = tabs->current;
5316 assert (tab_item->tc->type == TERM_CONTAINER_TYPE_SOLO);
5317 solo = (Solo*)tab_item->tc;
5318 term = solo->term;
5319
5320
5321 // this is all below just for tab bar at the top
5322 if (term->config->show_tabs)
5323 {
5324 _tabbar_clear(term);
5325
5326 if (!term->tab_spacer)
5327 {
5328 term->tab_spacer = evas_object_rectangle_add(evas_object_evas_get(term->bg));
5329 evas_object_color_set(term->tab_spacer, 0, 0, 0, 0);
5330 }
5331 elm_coords_finger_size_adjust(1, &w, 1, &h);
5332 evas_object_size_hint_min_set(term->tab_spacer, w, h);
5333 elm_layout_content_set(term->bg, "terminology.tab_btn",
5334 term->tab_spacer);
5335
5336 elm_layout_signal_emit(term->bg, "tabcount,off", "terminology");
5337
5338 elm_layout_signal_emit(term->bg, "tabbar,on", "terminology");
5339 elm_layout_signal_emit(term->bg, "tab_btn,on", "terminology");
5340 assert(term == _tab_item_to_term(tabs->current));
5341 _tabs_get_or_create_boxes(term, NULL);
5342 _tabbar_fill(tabs);
5343 edje_object_message_signal_process(term->bg_edj);
5344 }
5345 else
5346 {
5347 _tabcount_refresh(tabs);
5348 }
5349 }
5350
5351 static Tab_Item*
tab_item_new(Tabs * tabs,Term_Container * child)5352 tab_item_new(Tabs *tabs, Term_Container *child)
5353 {
5354 Tab_Item *tab_item;
5355 Solo *solo;
5356 Term *term;
5357
5358 tab_item = calloc(1, sizeof(Tab_Item));
5359 if (!tab_item)
5360 return NULL;
5361 tab_item->tc = child;
5362 assert(child != NULL);
5363 assert(child->type == TERM_CONTAINER_TYPE_SOLO);
5364 solo = (Solo*)child;
5365 term = solo->term;
5366 assert(term->tab_item == NULL);
5367 term->tab_item = tab_item;
5368
5369 tabs->tabs = eina_list_append(tabs->tabs, tab_item);
5370
5371 return tab_item;
5372 }
5373
5374 static void
_tabs_split(Term_Container * tc,Term_Container * _child EINA_UNUSED,Term * from,const char * cmd,Eina_Bool is_horizontal)5375 _tabs_split(Term_Container *tc,
5376 Term_Container *_child EINA_UNUSED,
5377 Term *from,
5378 const char *cmd,
5379 Eina_Bool is_horizontal)
5380 {
5381 tc->parent->split(tc->parent, tc, from, cmd, is_horizontal);
5382 }
5383
5384 static int
_tabs_split_direction(Term_Container * tc,Term_Container * child_orig EINA_UNUSED,Term_Container * child_new,Split_Direction direction)5385 _tabs_split_direction(Term_Container *tc,
5386 Term_Container *child_orig EINA_UNUSED,
5387 Term_Container *child_new,
5388 Split_Direction direction)
5389 {
5390 return tc->parent->split_direction(tc->parent, tc, child_new, direction);
5391 }
5392
5393 static Eina_Bool
_tabs_is_visible(const Term_Container * tc,const Term_Container * child)5394 _tabs_is_visible(const Term_Container *tc, const Term_Container *child)
5395 {
5396 Tabs *tabs;
5397 assert (tc->type == TERM_CONTAINER_TYPE_TABS);
5398 tabs = (Tabs*) tc;
5399 return child == tabs->current->tc;
5400 }
5401
5402
5403 static void
_tabs_detach(Term_Container * tc,Term_Container * solo_child)5404 _tabs_detach(Term_Container *tc, Term_Container *solo_child)
5405 {
5406 Evas_Object *o;
5407 assert (tc->type == TERM_CONTAINER_TYPE_TABS);
5408 assert (solo_child->type == TERM_CONTAINER_TYPE_SOLO);
5409
5410 _tabs_close(tc, solo_child);
5411 solo_child->is_focused = EINA_FALSE;
5412
5413 o = solo_child->get_evas_object(solo_child);
5414 evas_object_hide(o);
5415 solo_child->parent = (Term_Container*) solo_child->wn;
5416 }
5417
5418 static Term_Container *
_tabs_new(Term_Container * child,Term_Container * parent)5419 _tabs_new(Term_Container *child, Term_Container *parent)
5420 {
5421 Win *wn;
5422 Term_Container *tc;
5423 Tabs *tabs;
5424 Tab_Item *tab_item;
5425
5426 tabs = calloc(1, sizeof(Tabs));
5427 if (!tabs)
5428 {
5429 return NULL;
5430 }
5431
5432 wn = child->wn;
5433
5434 tc = (Term_Container*)tabs;
5435 tc->term_next = _tabs_term_next;
5436 tc->term_prev = _tabs_term_prev;
5437 tc->term_up = _tabs_term_up;
5438 tc->term_down = _tabs_term_down;
5439 tc->term_left = _tabs_term_left;
5440 tc->term_right = _tabs_term_right;
5441 tc->term_first = _tabs_term_first;
5442 tc->term_last = _tabs_term_last;
5443 tc->focused_term_get = _tabs_focused_term_get;
5444 tc->get_evas_object = _tabs_get_evas_object;
5445 tc->split = _tabs_split;
5446 tc->split_direction = _tabs_split_direction;
5447 tc->find_term_at_coords = _tabs_find_term_at_coords;
5448 tc->size_eval = _tabs_size_eval;
5449 tc->swallow = _tabs_swallow;
5450 tc->focus = _tabs_focus;
5451 tc->unfocus = _tabs_unfocus;
5452 tc->set_title = _tabs_set_title;
5453 tc->bell = _tabs_bell;
5454 tc->close = _tabs_close;
5455 tc->update = _tabs_update;
5456 tc->is_visible = _tabs_is_visible;
5457 tc->detach = _tabs_detach;
5458 tc->title = eina_stringshare_add("Terminology");
5459 tc->type = TERM_CONTAINER_TYPE_TABS;
5460
5461 tc->parent = parent;
5462 tc->wn = wn;
5463
5464 child->parent = tc;
5465 tab_item = tab_item_new(tabs, child);
5466 tabs->current = tab_item;
5467
5468 /* XXX: need to refresh */
5469 parent->swallow(parent, child, tc);
5470
5471 tc->is_focused = child->is_focused;
5472
5473 return tc;
5474 }
5475
5476
5477 /* }}} */
5478 /* {{{ Popup Media */
5479 struct Pop_Media {
5480 const char *src;
5481 Eina_Bool from_user_interaction;
5482 };
5483
5484 Eina_Bool
term_has_popmedia(const Term * term)5485 term_has_popmedia(const Term *term)
5486 {
5487 return !!term->popmedia;
5488 }
5489
5490 void
term_popmedia_close(Term * term)5491 term_popmedia_close(Term *term)
5492 {
5493 if (term->popmedia)
5494 elm_layout_signal_emit(term->bg, "popmedia,off", "terminology");
5495 }
5496
5497 static void
_cb_popmedia_del(void * data,Evas * _e EINA_UNUSED,Evas_Object * _o EINA_UNUSED,void * _event_info EINA_UNUSED)5498 _cb_popmedia_del(void *data,
5499 Evas *_e EINA_UNUSED,
5500 Evas_Object *_o EINA_UNUSED,
5501 void *_event_info EINA_UNUSED)
5502 {
5503 Term *term = data;
5504
5505 term->popmedia = NULL;
5506 term->popmedia_deleted = EINA_TRUE;
5507 elm_layout_signal_emit(term->bg, "popmedia,off", "terminology");
5508 }
5509
5510 static void
_cb_popmedia_done(void * data,Evas_Object * _obj EINA_UNUSED,const char * _sig EINA_UNUSED,const char * _src EINA_UNUSED)5511 _cb_popmedia_done(void *data,
5512 Evas_Object *_obj EINA_UNUSED,
5513 const char *_sig EINA_UNUSED,
5514 const char *_src EINA_UNUSED)
5515 {
5516 Term *term = data;
5517
5518 if (term->popmedia || term->popmedia_deleted)
5519 {
5520 if (term->popmedia)
5521 {
5522 evas_object_event_callback_del(term->popmedia, EVAS_CALLBACK_DEL,
5523 _cb_popmedia_del);
5524 evas_object_del(term->popmedia);
5525 term->popmedia = NULL;
5526 }
5527 term->popmedia_deleted = EINA_FALSE;
5528 termio_mouseover_suspend_pushpop(term->termio, -1);
5529 _popmedia_queue_process(term);
5530 }
5531 }
5532
5533 static void
_cb_media_loop(void * data,Evas_Object * _obj EINA_UNUSED,void * _info EINA_UNUSED)5534 _cb_media_loop(void *data,
5535 Evas_Object *_obj EINA_UNUSED,
5536 void *_info EINA_UNUSED)
5537 {
5538 Term *term = data;
5539
5540 if (term->popmedia_queue)
5541 {
5542 if (term->popmedia)
5543 media_play_set(term->popmedia, EINA_FALSE);
5544 elm_layout_signal_emit(term->bg, "popmedia,off", "terminology");
5545 }
5546 }
5547
5548 static void
_popmedia_queue_free(Term * term)5549 _popmedia_queue_free(Term *term)
5550 {
5551 struct Pop_Media *pm;
5552 if (!term->popmedia_queue)
5553 return;
5554
5555 EINA_LIST_FREE(term->popmedia_queue, pm)
5556 {
5557 eina_stringshare_del(pm->src);
5558 free(pm);
5559 }
5560 }
5561
5562 static void
_popmedia_queue_add(Term * term,const char * src,Eina_Bool from_user_interaction)5563 _popmedia_queue_add(Term *term, const char *src,
5564 Eina_Bool from_user_interaction)
5565 {
5566 struct Pop_Media *pm = calloc(1, sizeof(struct Pop_Media));
5567
5568 if (!pm)
5569 return;
5570
5571 pm->src = eina_stringshare_add(src);
5572 pm->from_user_interaction = from_user_interaction;
5573
5574 term->popmedia_queue = eina_list_append(term->popmedia_queue, pm);
5575 if (!term->popmedia)
5576 _popmedia_queue_process(term);
5577 }
5578
5579 static void
_popmedia_now(Term * term,const char * src,Eina_Bool from_user_interaction)5580 _popmedia_now(Term *term, const char *src,
5581 Eina_Bool from_user_interaction)
5582 {
5583 struct Pop_Media *pm;
5584
5585 /* Flush queue */
5586 EINA_LIST_FREE(term->popmedia_queue, pm)
5587 {
5588 eina_stringshare_del(pm->src);
5589 }
5590 elm_layout_signal_emit(term->bg, "popmedia,off", "terminology");
5591
5592 _popmedia_queue_add(term, src, from_user_interaction);
5593 }
5594
5595
5596 static void
_popmedia_show(Term * term,const char * src,Media_Type type)5597 _popmedia_show(Term *term, const char *src, Media_Type type)
5598 {
5599 Evas_Object *o;
5600 Config *config = termio_config_get(term->termio);
5601
5602 assert(!term->popmedia);
5603 EINA_SAFETY_ON_NULL_RETURN(config);
5604 termio_mouseover_suspend_pushpop(term->termio, 1);
5605 term->popmedia = o = media_add(win_evas_object_get(term->wn),
5606 src, config, MEDIA_POP, type);
5607 term->popmedia_deleted = EINA_FALSE;
5608 evas_object_smart_callback_add(o, "loop", _cb_media_loop, term);
5609 evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, _cb_popmedia_del, term);
5610 elm_layout_content_set(term->bg, "terminology.popmedia", o);
5611 evas_object_show(o);
5612 term->poptype = type;
5613 switch (type)
5614 {
5615 case MEDIA_TYPE_IMG:
5616 elm_layout_signal_emit(term->bg, "popmedia,image", "terminology");
5617 break;
5618 case MEDIA_TYPE_SCALE:
5619 elm_layout_signal_emit(term->bg, "popmedia,scale", "terminology");
5620 break;
5621 case MEDIA_TYPE_EDJE:
5622 elm_layout_signal_emit(term->bg, "popmedia,edje", "terminology");
5623 break;
5624 case MEDIA_TYPE_MOV:
5625 elm_layout_signal_emit(term->bg, "popmedia,movie", "terminology");
5626 break;
5627 case MEDIA_TYPE_UNKNOWN:
5628 default:
5629 break;
5630 }
5631 }
5632
5633 #ifdef HAVE_ECORE_CON_URL_HEAD
5634 typedef struct _Ty_Http_Head {
5635 const char *handler;
5636 const char *src;
5637 Ecore_Con_Url *url;
5638 Ecore_Event_Handler *url_complete;
5639 Ecore_Timer *timeout;
5640 Term *term;
5641 Eina_Bool fallback_allowed;
5642 } Ty_Http_Head;
5643
5644 static void
_ty_http_head_delete(Ty_Http_Head * ty_head)5645 _ty_http_head_delete(Ty_Http_Head *ty_head)
5646 {
5647 eina_stringshare_del(ty_head->handler);
5648 eina_stringshare_del(ty_head->src);
5649 ecore_con_url_free(ty_head->url);
5650 ecore_event_handler_del(ty_head->url_complete);
5651 if (ty_head->term)
5652 {
5653 elm_layout_signal_emit(ty_head->term->bg, "done", "terminology");
5654 term_unref(ty_head->term);
5655 }
5656 ecore_timer_del(ty_head->timeout);
5657
5658 free(ty_head);
5659 }
5660
5661 static Eina_Bool
_media_http_head_timeout(void * data)5662 _media_http_head_timeout(void *data)
5663 {
5664 Ty_Http_Head *ty_head = data;
5665
5666 ty_head->timeout = NULL;
5667 if (ty_head->fallback_allowed)
5668 {
5669 media_unknown_handle(ty_head->handler, ty_head->src);
5670 }
5671 _ty_http_head_delete(ty_head);
5672 return ECORE_CALLBACK_CANCEL;
5673 }
5674
5675 static Eina_Bool
_media_http_head_complete(void * data,int _kind EINA_UNUSED,void * event_info)5676 _media_http_head_complete(void *data,
5677 int _kind EINA_UNUSED,
5678 void *event_info)
5679 {
5680 Ecore_Con_Event_Url_Complete *ev = event_info;
5681 Ty_Http_Head *ty_head = data;
5682 const Eina_List *headers, *l;
5683 Media_Type type = MEDIA_TYPE_UNKNOWN;
5684 char *str;
5685
5686 if (ev->status != 200)
5687 goto error;
5688 headers = ecore_con_url_response_headers_get(ev->url_con);
5689 EINA_LIST_FOREACH(headers, l, str)
5690 {
5691 #define _CONTENT_TYPE_HDR "Content-Type: "
5692 #define _LOCATION_HDR "Location: "
5693 if (!strncmp(str, _LOCATION_HDR, strlen(_LOCATION_HDR)))
5694 {
5695 unsigned int len;
5696
5697 str += strlen(_LOCATION_HDR);
5698 if (*str != '/')
5699 {
5700 eina_stringshare_del(ty_head->src);
5701
5702 /* skip the crlf */
5703 len = strlen(str);
5704 if (len <= 2)
5705 goto error;
5706
5707 ty_head->src = eina_stringshare_add_length(str, len - 2);
5708 if (!ty_head->src)
5709 goto error;
5710 }
5711 }
5712 else if (!strncmp(str, _CONTENT_TYPE_HDR, strlen(_CONTENT_TYPE_HDR)))
5713 {
5714 str += strlen(_CONTENT_TYPE_HDR);
5715 if (!strncmp(str, "image/", strlen("image/")))
5716 {
5717 type = MEDIA_TYPE_IMG;
5718 }
5719 else if (!strncmp(str, "video/", strlen("video/")))
5720 {
5721 type = MEDIA_TYPE_MOV;
5722 }
5723 if (type != MEDIA_TYPE_UNKNOWN)
5724 {
5725 _popmedia_show(ty_head->term, ty_head->src, type);
5726 break;
5727 }
5728 }
5729 #undef _CONTENT_TYPE_HDR
5730 #undef _LOCATION_HDR
5731 }
5732 if (type == MEDIA_TYPE_UNKNOWN)
5733 goto error;
5734
5735 _ty_http_head_delete(ty_head);
5736 return EINA_TRUE;
5737 error:
5738 if (ty_head->fallback_allowed)
5739 {
5740 media_unknown_handle(ty_head->handler, ty_head->src);
5741 }
5742 _ty_http_head_delete(ty_head);
5743 return EINA_TRUE;
5744 }
5745 #endif
5746
5747 static void
_popmedia_unknown(Term * term,const char * src,Eina_Bool from_user_interaction)5748 _popmedia_unknown(Term *term, const char *src, Eina_Bool from_user_interaction)
5749 {
5750 Media_Type type;
5751 Config *config = termio_config_get(term->termio);
5752
5753 type = media_src_type_get(src);
5754 if (type == MEDIA_TYPE_UNKNOWN)
5755 {
5756 #ifdef HAVE_ECORE_CON_URL_HEAD
5757 Ty_Http_Head *ty_head = calloc(1, sizeof(Ty_Http_Head));
5758 if (!ty_head)
5759 return;
5760
5761 if (config->helper.local.general && config->helper.local.general[0])
5762 {
5763 ty_head->handler = eina_stringshare_add(config->helper.local.general);
5764 if (!ty_head->handler)
5765 goto error;
5766 }
5767 /* If it comes from a user interaction (click on a link), allow
5768 * fallback to "xdg-open"
5769 * Otherwise, it's from terminology's escape code. Thus don't allow
5770 * fallback and only display content "inline".
5771 */
5772 ty_head->fallback_allowed = from_user_interaction;
5773 ty_head->src = eina_stringshare_add(src);
5774 if (!ty_head->src)
5775 goto error;
5776 ty_head->url = ecore_con_url_new(src);
5777 if (!ty_head->url)
5778 goto error;
5779 if (!ecore_con_url_head(ty_head->url))
5780 goto error;
5781 ty_head->url_complete = ecore_event_handler_add
5782 (ECORE_CON_EVENT_URL_COMPLETE, _media_http_head_complete, ty_head);
5783 ty_head->timeout = ecore_timer_add(2.5, _media_http_head_timeout, ty_head);
5784 if (!ty_head->url_complete)
5785 goto error;
5786 ty_head->term = term;
5787 elm_layout_signal_emit(term->bg, "busy", "terminology");
5788 term_ref(term);
5789 return;
5790
5791 error:
5792 _ty_http_head_delete(ty_head);
5793 #endif
5794 if (from_user_interaction)
5795 {
5796 media_unknown_handle(config->helper.local.general, src);
5797 }
5798 }
5799 else
5800 {
5801 _popmedia_show(term, src, type);
5802 }
5803 }
5804
5805 static void
_popmedia_queue_process(Term * term)5806 _popmedia_queue_process(Term *term)
5807 {
5808 struct Pop_Media *pm;
5809
5810 if (!term->popmedia_queue)
5811 return;
5812 pm = term->popmedia_queue->data;
5813 term->popmedia_queue = eina_list_remove_list(term->popmedia_queue,
5814 term->popmedia_queue);
5815 if (!pm)
5816 return;
5817 _popmedia_unknown(term, pm->src, pm->from_user_interaction);
5818 eina_stringshare_del(pm->src);
5819 free(pm);
5820 }
5821
5822 static void
_cb_popup(void * data,Evas_Object * _obj EINA_UNUSED,void * event)5823 _cb_popup(void *data,
5824 Evas_Object *_obj EINA_UNUSED,
5825 void *event)
5826 {
5827 Term *term = data;
5828 const char *src = event;
5829 Eina_Bool from_user_interaction = EINA_FALSE;
5830
5831 if (!src)
5832 {
5833 /* Popup a link, there was user interaction on it. */
5834 from_user_interaction = EINA_TRUE;
5835 src = termio_link_get(term->termio, NULL);
5836 }
5837 if (!src)
5838 return;
5839 _popmedia_unknown(term, src, from_user_interaction);
5840 if (!event)
5841 free((void*)src);
5842 }
5843
5844 static void
_cb_popup_queue(void * data,Evas_Object * _obj EINA_UNUSED,void * event)5845 _cb_popup_queue(void *data,
5846 Evas_Object *_obj EINA_UNUSED,
5847 void *event)
5848 {
5849 Term *term = data;
5850 const char *src = event;
5851 Eina_Bool from_user_interaction = EINA_FALSE;
5852
5853 if (!src)
5854 {
5855 from_user_interaction = EINA_TRUE;
5856 src = termio_link_get(term->termio, NULL);
5857 }
5858 if (!src)
5859 return;
5860 _popmedia_queue_add(term, src, from_user_interaction);
5861 if (!event)
5862 free((void*)src);
5863 }
5864
5865 /* }}} */
5866 /* {{{ Term */
5867
5868 Eina_Bool
term_is_visible(const Term * term)5869 term_is_visible(const Term *term)
5870 {
5871 const Term_Container *tc;
5872
5873 if (!term)
5874 return EINA_FALSE;
5875
5876 tc = term->container;
5877 if (!tc)
5878 return EINA_FALSE;
5879
5880 return tc->is_visible(tc, tc);
5881 }
5882
5883 void
background_set_shine(const Config * config,Evas_Object * bg_edj)5884 background_set_shine(const Config *config, Evas_Object *bg_edj)
5885 {
5886 Edje_Message_Int msg;
5887
5888 if (config)
5889 msg.val = config->shine;
5890 else
5891 msg.val = 255;
5892
5893 if (bg_edj)
5894 edje_object_message_send(bg_edj, EDJE_MESSAGE_INT, 2, &msg);
5895 }
5896
5897 void
term_apply_shine(Term * term,int shine)5898 term_apply_shine(Term *term, int shine)
5899 {
5900 Config *config = term->config;
5901
5902 if (config->shine != shine)
5903 {
5904 config->shine = shine;
5905 background_set_shine(config, term->bg_edj);
5906 config_save(config);
5907 }
5908 }
5909
5910
5911 static void
_term_config_set(Term * term,Config * config)5912 _term_config_set(Term *term, Config *config)
5913 {
5914 Config *old_config = term->config;
5915
5916 term->config = config;
5917 termio_config_set(term->termio, config);
5918 _term_media_update(term, term->config);
5919 if (old_config != term->wn->config)
5920 config_del(old_config);
5921 }
5922
5923 Eina_Bool
term_is_focused(const Term * term)5924 term_is_focused(const Term *term)
5925 {
5926 Term_Container *tc;
5927
5928 if (!term)
5929 return EINA_FALSE;
5930
5931 tc = term->container;
5932 if (!tc)
5933 return EINA_FALSE;
5934
5935 return tc->is_focused;
5936 }
5937
change_theme(Evas_Object * win,Config * config)5938 void change_theme(Evas_Object *win, Config *config)
5939 {
5940 const Eina_List *terms, *l;
5941 Term *term;
5942
5943 terms = terms_from_win_object(win);
5944 if (!terms) return;
5945
5946 EINA_LIST_FOREACH(terms, l, term)
5947 {
5948 if (!theme_apply(term->bg, config, "terminology/background",
5949 NULL, NULL, EINA_TRUE))
5950 ERR("Couldn't find terminology theme!");
5951 colors_term_init(termio_textgrid_get(term->termio),
5952 config->color_scheme);
5953 termio_config_set(term->termio, config);
5954 }
5955
5956 l = elm_theme_overlay_list_get(NULL);
5957 if (l) l = eina_list_last(l);
5958 if (l) elm_theme_overlay_del(NULL, l->data);
5959 elm_theme_overlay_add(NULL, config_theme_path_get(config));
5960 main_trans_update();
5961 }
5962
5963 void
term_focus(Term * term)5964 term_focus(Term *term)
5965 {
5966 Term_Container *tc;
5967
5968 DBG("is focused? tc:%p", term->container);
5969 if (term_is_focused(term))
5970 return;
5971
5972 tc = term->container;
5973 DBG("tc:%p", tc);
5974 tc->focus(tc, tc);
5975 }
5976
5977 void
term_unfocus(Term * term)5978 term_unfocus(Term *term)
5979 {
5980 Term_Container *tc;
5981
5982 DBG("is focused? tc:%p", term->container);
5983 if (!term_is_focused(term))
5984 return;
5985
5986 tc = term->container;
5987 DBG("tc:%p", tc);
5988 tc->unfocus(tc, tc);
5989 }
5990
5991 enum term_to_direction {
5992 TERM_TO_PREV,
5993 TERM_TO_NEXT,
5994 TERM_TO_UP,
5995 TERM_TO_DOWN,
5996 TERM_TO_LEFT,
5997 TERM_TO_RIGHT,
5998 };
5999
6000 static void
term_go_to(Term * from,enum term_to_direction dir)6001 term_go_to(Term *from, enum term_to_direction dir)
6002 {
6003 Term *new_term, *focused_term;
6004 Win *wn = from->wn;
6005 Term_Container *tc;
6006
6007 tc = (Term_Container *) wn;
6008
6009 focused_term = tc->focused_term_get(tc);
6010 if (!focused_term)
6011 focused_term = from;
6012 tc = focused_term->container;
6013
6014 switch (dir)
6015 {
6016 case TERM_TO_PREV:
6017 new_term = tc->term_prev(tc, tc);
6018 break;
6019 case TERM_TO_NEXT:
6020 new_term = tc->term_next(tc, tc);
6021 break;
6022 case TERM_TO_UP:
6023 new_term = tc->term_up(tc, tc);
6024 break;
6025 case TERM_TO_DOWN:
6026 new_term = tc->term_down(tc, tc);
6027 break;
6028 case TERM_TO_LEFT:
6029 new_term = tc->term_left(tc, tc);
6030 break;
6031 case TERM_TO_RIGHT:
6032 new_term = tc->term_right(tc, tc);
6033 break;
6034 }
6035
6036 if (new_term && new_term != focused_term)
6037 term_focus(new_term);
6038
6039 /* TODO: get rid of it? */
6040 _term_miniview_check(from);
6041 }
6042
6043 void
term_prev(Term * term)6044 term_prev(Term *term)
6045 {
6046 term_go_to(term, TERM_TO_PREV);
6047 }
6048
6049 void
term_next(Term * term)6050 term_next(Term *term)
6051 {
6052 term_go_to(term, TERM_TO_NEXT);
6053 }
6054
6055 void
term_up(Term * term)6056 term_up(Term *term)
6057 {
6058 term_go_to(term, TERM_TO_UP);
6059 }
6060
6061 void
term_down(Term * term)6062 term_down(Term *term)
6063 {
6064 term_go_to(term, TERM_TO_DOWN);
6065 }
6066
6067 void
term_left(Term * term)6068 term_left(Term *term)
6069 {
6070 term_go_to(term, TERM_TO_LEFT);
6071 }
6072
6073 void
term_right(Term * term)6074 term_right(Term *term)
6075 {
6076 term_go_to(term, TERM_TO_RIGHT);
6077 }
6078
6079 Term *
term_prev_get(const Term * term)6080 term_prev_get(const Term *term)
6081 {
6082 Term_Container *tc = term->container;
6083
6084 return tc->term_prev(tc, tc);
6085 }
6086
6087 Term *
term_next_get(const Term * term)6088 term_next_get(const Term *term)
6089 {
6090 Term_Container *tc = term->container;
6091
6092 return tc->term_next(tc, tc);
6093 }
6094
6095
6096 static void
_term_miniview_check(Term * term)6097 _term_miniview_check(Term *term)
6098 {
6099 Eina_List *l, *wn_list;
6100
6101 EINA_SAFETY_ON_NULL_RETURN(term);
6102 EINA_SAFETY_ON_NULL_RETURN(term->miniview);
6103
6104 wn_list = win_terms_get(term_win_get(term));
6105
6106 EINA_LIST_FOREACH(wn_list, l, term)
6107 {
6108 if (term->miniview_shown)
6109 {
6110 DBG("is focused? tc:%p", term->container);
6111 if (term_is_focused(term))
6112 elm_layout_signal_emit(term->bg, "miniview,on", "terminology");
6113 }
6114 }
6115 }
6116
6117 void
term_miniview_hide(Term * term)6118 term_miniview_hide(Term *term)
6119 {
6120 EINA_SAFETY_ON_NULL_RETURN(term);
6121 EINA_SAFETY_ON_NULL_RETURN(term->miniview);
6122
6123 if (term->miniview_shown)
6124 {
6125 elm_layout_signal_emit(term->bg, "miniview,off", "terminology");
6126 term->miniview_shown = EINA_FALSE;
6127 }
6128 }
6129
6130 void
term_miniview_toggle(Term * term)6131 term_miniview_toggle(Term *term)
6132 {
6133 EINA_SAFETY_ON_NULL_RETURN(term);
6134 EINA_SAFETY_ON_NULL_RETURN(term->miniview);
6135
6136 if (term->miniview_shown)
6137 {
6138 elm_layout_signal_emit(term->bg, "miniview,off", "terminology");
6139 term->miniview_shown = EINA_FALSE;
6140 }
6141 else
6142 {
6143 elm_layout_signal_emit(term->bg, "miniview,on", "terminology");
6144 term->miniview_shown = EINA_TRUE;
6145 }
6146 }
6147
6148 static void
_on_popover_done(Win * wn)6149 _on_popover_done(Win *wn)
6150 {
6151 Term_Container *tc = (Term_Container*) wn;
6152 Eina_List *l;
6153 Term *term;
6154
6155 wn->on_popover--;
6156 if (wn->on_popover)
6157 return;
6158
6159 if (!_win_is_focused(wn))
6160 return;
6161 EINA_LIST_FOREACH(wn->terms, l, term)
6162 {
6163 DBG("is focused? tc:%p", term->container);
6164 if (term_is_focused(term))
6165 return;
6166 }
6167 DBG("focus tc:%p", tc);
6168 tc->focus(tc, tc);
6169 }
6170
6171 static void
_set_title_ok_cb(void * data,Evas_Object * _obj EINA_UNUSED,void * _event_info EINA_UNUSED)6172 _set_title_ok_cb(void *data,
6173 Evas_Object *_obj EINA_UNUSED,
6174 void *_event_info EINA_UNUSED)
6175 {
6176 Evas_Object *popup = data;
6177 Term *term = evas_object_data_get(popup, "term");
6178 Evas_Object *entry = elm_object_content_get(popup);
6179 const char *title = elm_entry_entry_get(entry);
6180
6181 if (!title || !strlen(title))
6182 title = NULL;
6183
6184 termio_user_title_set(term->termio, title);
6185 elm_object_focus_set(entry, EINA_FALSE);
6186 elm_popup_dismiss(popup);
6187 }
6188
6189 static void
_set_title_cancel_cb(void * data,Evas_Object * _obj EINA_UNUSED,void * _event_info EINA_UNUSED)6190 _set_title_cancel_cb(void *data,
6191 Evas_Object *_obj EINA_UNUSED,
6192 void *_event_info EINA_UNUSED)
6193 {
6194 Evas_Object *popup = data;
6195 Evas_Object *entry = elm_object_content_get(popup);
6196
6197 elm_object_focus_set(entry, EINA_FALSE);
6198 elm_popup_dismiss(popup);
6199 }
6200
6201 static void
_cb_title_popup_hide(void * data,Evas * _e EINA_UNUSED,Evas_Object * _obj EINA_UNUSED,void * _event EINA_UNUSED)6202 _cb_title_popup_hide(void *data,
6203 Evas *_e EINA_UNUSED,
6204 Evas_Object *_obj EINA_UNUSED,
6205 void *_event EINA_UNUSED)
6206 {
6207 Term *term = data;
6208 Win *wn = term->wn;
6209
6210 _on_popover_done(wn);
6211
6212 term_unref(term);
6213 }
6214
6215 void
term_set_title(Term * term)6216 term_set_title(Term *term)
6217 {
6218 Evas_Object *o;
6219 Evas_Object *popup;
6220 Term_Container *tc = term->container;
6221 const char *prev_title;
6222
6223 EINA_SAFETY_ON_NULL_RETURN(term);
6224 term->wn->on_popover++;
6225
6226 term_ref(term);
6227 tc->unfocus(tc, NULL);
6228
6229 popup = elm_popup_add(term->wn->win);
6230 evas_object_data_set(popup, "term", term);
6231 evas_object_event_callback_add(popup, EVAS_CALLBACK_HIDE,
6232 _cb_title_popup_hide, term);
6233
6234 elm_object_part_text_set(popup, "title,text", _("Set title"));
6235
6236 o = elm_button_add(popup);
6237 evas_object_smart_callback_add(o, "clicked", _set_title_ok_cb, popup);
6238 elm_object_text_set(o, _("Ok"));
6239 elm_object_part_content_set(popup, "button1", o);
6240
6241 o = elm_button_add(popup);
6242 evas_object_smart_callback_add(o, "clicked", _set_title_cancel_cb, popup);
6243 elm_object_text_set(o, _("Cancel"));
6244 elm_object_part_content_set(popup, "button2", o);
6245
6246 o = elm_entry_add(popup);
6247 elm_entry_single_line_set(o, EINA_TRUE);
6248 elm_entry_editable_set(o, EINA_TRUE);
6249 prev_title = termio_user_title_get(term->termio);
6250 if (prev_title)
6251 {
6252 elm_entry_entry_set(o, prev_title);
6253 elm_entry_cursor_pos_set(o, strlen(prev_title));
6254 }
6255 evas_object_smart_callback_add(o, "activated", _set_title_ok_cb, popup);
6256 evas_object_smart_callback_add(o, "aborted", _set_title_cancel_cb, popup);
6257 elm_object_content_set(popup, o);
6258
6259 evas_object_show(o);
6260
6261 evas_object_show(popup);
6262
6263 elm_object_focus_set(o, EINA_TRUE);
6264 }
6265
6266 static void
_set_alpha(Config * config,const char * val,Eina_Bool save)6267 _set_alpha(Config *config, const char *val, Eina_Bool save)
6268 {
6269 int opacity;
6270
6271 if (!config || !val) return;
6272
6273 config->temporary = !save;
6274
6275 if (isdigit(*val))
6276 {
6277 opacity = atoi(val);
6278 if (opacity >= 100)
6279 {
6280 config->translucent = EINA_FALSE;
6281 config->opacity = 100;
6282 }
6283 else if (opacity >= 0)
6284 {
6285 config->translucent = EINA_TRUE;
6286 config->opacity = opacity;
6287 }
6288 }
6289 else if ((!strcasecmp(val, "on")) ||
6290 (!strcasecmp(val, "true")) ||
6291 (!strcasecmp(val, "yes")))
6292 config->translucent = EINA_TRUE;
6293 else
6294 config->translucent = EINA_FALSE;
6295 if (save)
6296 config_save(config);
6297 main_trans_update();
6298 }
6299
6300 static void
_sendfile_progress_del(void * data EINA_UNUSED,Evas * e EINA_UNUSED,Evas_Object * obj,void * info EINA_UNUSED)6301 _sendfile_progress_del(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED)
6302 {
6303 Evas_Object *o = obj;
6304 Term *term = evas_object_data_get(o, "sendfile-progress-term");
6305 Ecore_Timer *t;
6306
6307 evas_object_data_del(o, "sendfile-progress-term");
6308 if (term)
6309 {
6310 term->sendfile_progress = NULL;
6311 term->sendfile_progress_bar = NULL;
6312 }
6313 t = evas_object_data_get(o, "sendfile-progress-timer");
6314 evas_object_data_del(o, "sendfile-progress-term");
6315 if (t) ecore_timer_del(t);
6316 }
6317
6318 static Eina_Bool
_sendfile_progress_reset(void * data)6319 _sendfile_progress_reset(void *data)
6320 {
6321 Evas_Object *o = data;
6322 Term *term = evas_object_data_get(o, "sendfile-progress-term");
6323
6324 if (term)
6325 {
6326 term->sendfile_progress = NULL;
6327 term->sendfile_progress_bar = NULL;
6328 }
6329 evas_object_data_del(o, "sendfile-progress-timer");
6330 evas_object_data_del(o, "sendfile-progress-term");
6331 evas_object_del(o);
6332 return EINA_FALSE;
6333 }
6334
6335 static Eina_Bool
_sendfile_progress_hide_delay(void * data)6336 _sendfile_progress_hide_delay(void *data)
6337 {
6338 Term *term = data;
6339 Ecore_Timer *t;
6340
6341 term->sendfile_progress_hide_timer = NULL;
6342 if (!term->sendfile_progress_enabled) return EINA_FALSE;
6343 term->sendfile_progress_enabled = EINA_FALSE;
6344 elm_layout_signal_emit(term->bg, "sendfile,progress,off", "terminology");
6345 t = evas_object_data_get(term->sendfile_progress, "sendfile-progress-timer");
6346 if (t) ecore_timer_del(t);
6347 t = ecore_timer_add(10.0, _sendfile_progress_reset, term->sendfile_progress);
6348 evas_object_data_set(term->sendfile_progress, "sendfile-progress-timer", t);
6349 return EINA_FALSE;
6350 }
6351
6352 static void
_sendfile_progress_hide(Term * term)6353 _sendfile_progress_hide(Term *term)
6354 {
6355 if (!term->sendfile_progress_enabled) return;
6356 if (term->sendfile_progress_hide_timer)
6357 ecore_timer_del(term->sendfile_progress_hide_timer);
6358 term->sendfile_progress_hide_timer =
6359 ecore_timer_add(0.5, _sendfile_progress_hide_delay, term);
6360 if (elm_object_focus_get(term->sendfile_progress))
6361 {
6362 elm_object_focus_set(term->sendfile_progress, EINA_FALSE);
6363 term_focus(term);
6364 }
6365 }
6366
6367 static void
_sendfile_progress_cancel(void * data,Evas_Object * obj EINA_UNUSED,void * info EINA_UNUSED)6368 _sendfile_progress_cancel(void *data, Evas_Object *obj EINA_UNUSED, void *info EINA_UNUSED)
6369 {
6370 Term *term = data;
6371
6372 if (!term->sendfile_progress) return;
6373 termio_file_send_cancel(term->termio);
6374 _sendfile_progress_hide(term);
6375 }
6376
6377 static void
_sendfile_progress(Term * term)6378 _sendfile_progress(Term *term)
6379 {
6380 Evas_Object *o, *base;
6381
6382 if (term->sendfile_progress)
6383 {
6384 evas_object_del(term->sendfile_progress);
6385 term->sendfile_progress = NULL;
6386 }
6387 if (!edje_object_part_exists(term->bg_edj, "terminology.sendfile.progress"))
6388 {
6389 return;
6390 }
6391 if (term->sendfile_progress_hide_timer)
6392 {
6393 ecore_timer_del(term->sendfile_progress_hide_timer);
6394 term->sendfile_progress_hide_timer = NULL;
6395 }
6396 o = elm_box_add(term->wn->win);
6397 evas_object_data_set(o, "sendfile-progress-term", term);
6398 base = o;
6399 term->sendfile_progress = o;
6400 evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, _sendfile_progress_del, NULL);
6401 elm_box_horizontal_set(o, EINA_TRUE);
6402
6403 o = elm_button_add(term->wn->win);
6404 elm_object_text_set(o, "Cancel");
6405 evas_object_smart_callback_add(o, "clicked", _sendfile_progress_cancel, term);
6406 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
6407 elm_box_pack_end(base, o);
6408 evas_object_show(o);
6409
6410 o = elm_progressbar_add(term->wn->win);
6411 term->sendfile_progress_bar = o;
6412 elm_progressbar_unit_format_set(o, "%1.0f%%");
6413 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
6414 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
6415 elm_box_pack_end(base, o);
6416 evas_object_show(o);
6417
6418 term->sendfile_progress_enabled = EINA_TRUE;
6419 elm_layout_content_set(term->bg, "terminology.sendfile.progress", base);
6420 evas_object_show(base);
6421 elm_layout_signal_emit(term->bg, "sendfile,progress,on", "terminology");
6422 }
6423
6424 static void
_sendfile_request_del(void * data EINA_UNUSED,Evas * e EINA_UNUSED,Evas_Object * obj,void * info EINA_UNUSED)6425 _sendfile_request_del(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED)
6426 {
6427 Evas_Object *o = obj;
6428 Term *term = evas_object_data_get(o, "sendfile-request-term");
6429 Ecore_Timer *t;
6430
6431 evas_object_data_del(o, "sendfile-request-term");
6432 if (term) term->sendfile_request = NULL;
6433 t = evas_object_data_get(o, "sendfile-request-timer");
6434 evas_object_data_del(o, "sendfile-request-term");
6435 if (t) ecore_timer_del(t);
6436 }
6437
6438 static Eina_Bool
_sendfile_request_reset(void * data)6439 _sendfile_request_reset(void *data)
6440 {
6441 Evas_Object *o = data;
6442 Term *term = evas_object_data_get(o, "sendfile-request-term");
6443
6444 if (term) term->sendfile_request = NULL;
6445 evas_object_data_del(o, "sendfile-request-timer");
6446 evas_object_data_del(o, "sendfile-request-term");
6447 evas_object_del(o);
6448 return EINA_FALSE;
6449 }
6450
6451 static Eina_Bool
_sendfile_request_hide_delay(void * data)6452 _sendfile_request_hide_delay(void *data)
6453 {
6454 Term *term = data;
6455 Ecore_Timer *t;
6456
6457 term->sendfile_request_hide_timer = NULL;
6458 if (!term->sendfile_request_enabled) return EINA_FALSE;
6459 term->sendfile_request_enabled = EINA_FALSE;
6460 elm_layout_signal_emit(term->bg, "sendfile,request,off", "terminology");
6461 t = evas_object_data_get(term->sendfile_request, "sendfile-request-timer");
6462 if (t) ecore_timer_del(t);
6463 t = ecore_timer_add(10.0, _sendfile_request_reset, term->sendfile_request);
6464 evas_object_data_set(term->sendfile_request, "sendfile-request-timer", t);
6465 if (elm_object_focus_get(term->sendfile_request))
6466 {
6467 elm_object_focus_set(term->sendfile_request, EINA_FALSE);
6468 term_focus(term);
6469 }
6470 return EINA_FALSE;
6471 }
6472
6473 static void
_sendfile_request_hide(Term * term)6474 _sendfile_request_hide(Term *term)
6475 {
6476 if (!term->sendfile_request_enabled) return;
6477 if (term->sendfile_request_hide_timer)
6478 ecore_timer_del(term->sendfile_request_hide_timer);
6479 term->sendfile_request_hide_timer =
6480 ecore_timer_add(0.2, _sendfile_request_hide_delay, term);
6481 }
6482
6483 static void
_sendfile_request_done(void * data,Evas_Object * obj EINA_UNUSED,void * info)6484 _sendfile_request_done(void *data, Evas_Object *obj EINA_UNUSED, void *info)
6485 {
6486 Term *term = data;
6487 const char *path, *selpath = info;
6488
6489 if (!term->sendfile_request) return;
6490
6491 path = elm_fileselector_path_get(term->sendfile_request);
6492 eina_stringshare_replace(&term->sendfile_dir, path);
6493
6494 if (selpath)
6495 {
6496 _sendfile_progress(term);
6497 termio_file_send_ok(term->termio, selpath);
6498 }
6499 else termio_file_send_cancel(term->termio);
6500 _sendfile_request_hide(term);
6501 }
6502
6503 static void
_sendfile_request(Term * term,const char * path)6504 _sendfile_request(Term *term, const char *path)
6505 {
6506 Evas_Object *o;
6507 const char *p;
6508
6509 if (term->sendfile_request)
6510 {
6511 evas_object_del(term->sendfile_request);
6512 term->sendfile_request = NULL;
6513 }
6514 if (!edje_object_part_exists(term->bg_edj, "terminology.sendfile.request"))
6515 {
6516 termio_file_send_cancel(term->termio);
6517 return;
6518 }
6519 if (term->sendfile_request_hide_timer)
6520 {
6521 ecore_timer_del(term->sendfile_request_hide_timer);
6522 term->sendfile_request_hide_timer = NULL;
6523 }
6524 o = elm_fileselector_add(term->wn->win);
6525 evas_object_data_set(o, "sendfile-request-term", term);
6526 term->sendfile_request = o;
6527 evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, _sendfile_request_del, NULL);
6528 elm_fileselector_is_save_set(o, EINA_TRUE);
6529 elm_fileselector_expandable_set(o, EINA_FALSE);
6530 if (!term->sendfile_dir)
6531 {
6532 const char *dir = eina_environment_home_get();
6533
6534 if (dir) term->sendfile_dir = eina_stringshare_add(dir);
6535 }
6536 if (term->sendfile_dir) elm_fileselector_path_set(o, term->sendfile_dir);
6537 p = strrchr(path, '/');
6538 if (p) elm_fileselector_current_name_set(o, p + 1);
6539 else elm_fileselector_current_name_set(o, path);
6540 evas_object_smart_callback_add(o, "done", _sendfile_request_done, term);
6541 term->sendfile_request_enabled = EINA_TRUE;
6542 elm_layout_content_set(term->bg, "terminology.sendfile.request", o);
6543 evas_object_show(o);
6544 elm_layout_signal_emit(term->bg, "sendfile,request,on", "terminology");
6545 elm_object_focus_set(o, EINA_TRUE);
6546 }
6547
6548 static void
_cb_command(void * data,Evas_Object * _obj EINA_UNUSED,void * event)6549 _cb_command(void *data,
6550 Evas_Object *_obj EINA_UNUSED,
6551 void *event)
6552 {
6553 Term *term = data;
6554 const char *cmd = event;
6555
6556 if (cmd[0] == 'p') // popmedia
6557 {
6558 if (cmd[1] == 'n') // now
6559 {
6560 _popmedia_now(term, cmd + 2, EINA_FALSE);
6561 }
6562 else if (cmd[1] == 'q') // queue it to display after current one
6563 {
6564 _popmedia_queue_add(term, cmd + 2, EINA_FALSE);
6565 }
6566 }
6567 else if (cmd[0] == 'b') // set background
6568 {
6569 if (cmd[1] == 't') // temporary
6570 {
6571 Config *config = termio_config_get(term->termio);
6572
6573 if (config)
6574 {
6575 Config *new_config = config_fork(config);
6576
6577 new_config->temporary = EINA_TRUE;
6578 if (cmd[2])
6579 eina_stringshare_replace(&(new_config->background), cmd + 2);
6580 else
6581 eina_stringshare_replace(&(new_config->background), NULL);
6582 _term_config_set(term, new_config);
6583 }
6584 }
6585 else if (cmd[1] == 'p') // permanent
6586 {
6587 Config *config = termio_config_get(term->termio);
6588
6589 if (config)
6590 {
6591 config->temporary = EINA_FALSE;
6592 if (cmd[2])
6593 eina_stringshare_replace(&(config->background), cmd + 2);
6594 else
6595 eina_stringshare_replace(&(config->background), NULL);
6596 main_media_update(config);
6597 config_save(config);
6598 }
6599 }
6600 }
6601 else if (cmd[0] == 'a') // set alpha
6602 {
6603 if (cmd[1] == 't') // temporary
6604 _set_alpha(termio_config_get(term->termio), cmd + 2, EINA_FALSE);
6605 else if (cmd[1] == 'p') // permanent
6606 _set_alpha(termio_config_get(term->termio), cmd + 2, EINA_TRUE);
6607 }
6608 else if (cmd[0] == 'f') // file...
6609 {
6610 if (cmd[1] == 'r') // receive
6611 {
6612 _sendfile_request(term, cmd + 2);
6613 }
6614 else if (cmd[1] == 'd') // data packet
6615 {
6616 }
6617 else if (cmd[1] == 'x') // exit data stream
6618 {
6619 }
6620 }
6621 }
6622
6623 static void
_cb_tab_go(void * data,Evas_Object * _obj EINA_UNUSED,const char * _sig EINA_UNUSED,const char * _src EINA_UNUSED)6624 _cb_tab_go(void *data,
6625 Evas_Object *_obj EINA_UNUSED,
6626 const char *_sig EINA_UNUSED,
6627 const char *_src EINA_UNUSED)
6628 {
6629 _cb_select(data, NULL, NULL);
6630 }
6631
6632 static void
_cb_tab_new(void * data,Evas_Object * _obj EINA_UNUSED,const char * _sig EINA_UNUSED,const char * _src EINA_UNUSED)6633 _cb_tab_new(void *data,
6634 Evas_Object *_obj EINA_UNUSED,
6635 const char *_sig EINA_UNUSED,
6636 const char *_src EINA_UNUSED)
6637 {
6638 Term *term = data;
6639 main_new(term->termio);
6640 }
6641
6642 static void
_cb_prev(void * data,Evas_Object * _obj EINA_UNUSED,void * _event EINA_UNUSED)6643 _cb_prev(void *data,
6644 Evas_Object *_obj EINA_UNUSED,
6645 void *_event EINA_UNUSED)
6646 {
6647 Term *term = data;
6648
6649 term_prev(term);
6650 }
6651
6652 static void
_cb_next(void * data,Evas_Object * _obj EINA_UNUSED,void * _event EINA_UNUSED)6653 _cb_next(void *data,
6654 Evas_Object *_obj EINA_UNUSED,
6655 void *_event EINA_UNUSED)
6656 {
6657 Term *term = data;
6658
6659 term_next(term);
6660 }
6661
6662 static void
_cb_split_h(void * data,Evas_Object * _obj EINA_UNUSED,void * _event EINA_UNUSED)6663 _cb_split_h(void *data,
6664 Evas_Object *_obj EINA_UNUSED,
6665 void *_event EINA_UNUSED)
6666 {
6667 Term *term = data;
6668 Term_Container *tc = term->container;
6669
6670 assert(tc->type == TERM_CONTAINER_TYPE_SOLO);
6671 tc->split(tc, tc, term, NULL, EINA_TRUE);
6672 }
6673
6674 static void
_cb_split_v(void * data,Evas_Object * _obj EINA_UNUSED,void * _event EINA_UNUSED)6675 _cb_split_v(void *data,
6676 Evas_Object *_obj EINA_UNUSED,
6677 void *_event EINA_UNUSED)
6678 {
6679 Term *term = data;
6680 Term_Container *tc = term->container;
6681
6682 assert(tc->type == TERM_CONTAINER_TYPE_SOLO);
6683 tc->split(tc, tc, term, NULL, EINA_FALSE);
6684 }
6685
6686 static void
_cb_title(void * data,Evas_Object * _obj EINA_UNUSED,void * _event EINA_UNUSED)6687 _cb_title(void *data,
6688 Evas_Object *_obj EINA_UNUSED,
6689 void *_event EINA_UNUSED)
6690 {
6691 Term *term = data;
6692 Term_Container *tc = term->container;
6693 const char *title = termio_title_get(term->termio);
6694
6695 if (title)
6696 tc->set_title(tc, tc, title);
6697 }
6698
6699 static void
_cb_icon(void * data,Evas_Object * _obj EINA_UNUSED,void * _event EINA_UNUSED)6700 _cb_icon(void *data,
6701 Evas_Object *_obj EINA_UNUSED,
6702 void *_event EINA_UNUSED)
6703 {
6704 Term *term = data;
6705 DBG("is focused? tc:%p", term->container);
6706 if (term_is_focused(term))
6707 elm_win_icon_name_set(term->wn->win, termio_icon_name_get(term->termio));
6708 }
6709
6710 static void
_cb_send_progress(void * data,Evas_Object * _obj EINA_UNUSED,void * _event EINA_UNUSED)6711 _cb_send_progress(void *data,
6712 Evas_Object *_obj EINA_UNUSED,
6713 void *_event EINA_UNUSED)
6714 {
6715 Term *term = data;
6716
6717 elm_progressbar_value_set(term->sendfile_progress_bar,
6718 termio_file_send_progress_get(term->termio));
6719 }
6720
6721 static void
_cb_send_end(void * data,Evas_Object * _obj EINA_UNUSED,void * _event EINA_UNUSED)6722 _cb_send_end(void *data,
6723 Evas_Object *_obj EINA_UNUSED,
6724 void *_event EINA_UNUSED)
6725 {
6726 Term *term = data;
6727 if (!term->sendfile_progress) return;
6728 _sendfile_request_hide(term);
6729 _sendfile_progress_hide(term);
6730 }
6731
6732 static Eina_Bool
_cb_cmd_del(void * data)6733 _cb_cmd_del(void *data)
6734 {
6735 Win *wn = data;
6736
6737 wn->cmdbox_del_timer = NULL;
6738 if (wn->cmdbox)
6739 {
6740 evas_object_del(wn->cmdbox);
6741 wn->cmdbox = NULL;
6742 }
6743 return EINA_FALSE;
6744 }
6745
6746 static void
_cb_cmd_activated(void * data,Evas_Object * _obj EINA_UNUSED,void * _event EINA_UNUSED)6747 _cb_cmd_activated(void *data,
6748 Evas_Object *_obj EINA_UNUSED,
6749 void *_event EINA_UNUSED)
6750 {
6751 Win *wn = data;
6752 char *cmd = NULL;
6753 Term *term;
6754 Term_Container *tc;
6755
6756 elm_layout_signal_emit(wn->base, "cmdbox,hide", "terminology");
6757 tc = (Term_Container *) wn;
6758 term = tc->focused_term_get(tc);
6759 if (wn->cmdbox) cmd = (char *)elm_entry_entry_get(wn->cmdbox);
6760 if (cmd)
6761 {
6762 cmd = elm_entry_markup_to_utf8(cmd);
6763 if (cmd)
6764 {
6765 if (term)
6766 termcmd_do(term->termio, term->wn->win, term->bg, cmd);
6767 free(cmd);
6768 }
6769 }
6770 elm_object_focus_set(wn->base, EINA_TRUE);
6771 wn->cmdbox_up = EINA_FALSE;
6772 if (wn->cmdbox_del_timer) ecore_timer_del(wn->cmdbox_del_timer);
6773 wn->cmdbox_del_timer = ecore_timer_add(5.0, _cb_cmd_del, wn);
6774 }
6775
6776 static void
_cb_cmd_aborted(void * data,Evas_Object * _obj EINA_UNUSED,void * _event EINA_UNUSED)6777 _cb_cmd_aborted(void *data,
6778 Evas_Object *_obj EINA_UNUSED,
6779 void *_event EINA_UNUSED)
6780 {
6781 Win *wn = data;
6782
6783 elm_layout_signal_emit(wn->base, "cmdbox,hide", "terminology");
6784 elm_object_focus_set(wn->base, EINA_TRUE);
6785 wn->cmdbox_up = EINA_FALSE;
6786 if (wn->cmdbox_del_timer) ecore_timer_del(wn->cmdbox_del_timer);
6787 wn->cmdbox_del_timer = ecore_timer_add(5.0, _cb_cmd_del, wn);
6788 }
6789
6790 static void
_cb_cmd_changed(void * data,Evas_Object * _obj EINA_UNUSED,void * _event EINA_UNUSED)6791 _cb_cmd_changed(void *data,
6792 Evas_Object *_obj EINA_UNUSED,
6793 void *_event EINA_UNUSED)
6794 {
6795 Win *wn = data;
6796 char *cmd = NULL;
6797 Term *term;
6798 Term_Container *tc;
6799
6800 tc = (Term_Container *) wn;
6801 term = tc->focused_term_get(tc);
6802 if (!term) return;
6803 if (wn->cmdbox) cmd = (char *)elm_entry_entry_get(wn->cmdbox);
6804 if (cmd)
6805 {
6806 cmd = elm_entry_markup_to_utf8(cmd);
6807 if (cmd)
6808 {
6809 termcmd_watch(term->termio, term->wn->win, term->bg, cmd);
6810 free(cmd);
6811 }
6812 }
6813 }
6814
6815 static void
_cb_cmd_hints_changed(void * data,Evas * _e EINA_UNUSED,Evas_Object * _obj EINA_UNUSED,void * _event_info EINA_UNUSED)6816 _cb_cmd_hints_changed(void *data,
6817 Evas *_e EINA_UNUSED,
6818 Evas_Object *_obj EINA_UNUSED,
6819 void *_event_info EINA_UNUSED)
6820 {
6821 Win *wn = data;
6822
6823 if (wn->cmdbox)
6824 {
6825 evas_object_show(wn->cmdbox);
6826 elm_layout_content_set(wn->base, "terminology.cmdbox", wn->cmdbox);
6827 }
6828 }
6829
6830 static void
_cb_cmdbox(void * data,Evas_Object * _obj EINA_UNUSED,void * _event EINA_UNUSED)6831 _cb_cmdbox(void *data,
6832 Evas_Object *_obj EINA_UNUSED,
6833 void *_event EINA_UNUSED)
6834 {
6835 Term *term = data;
6836
6837 term->wn->cmdbox_up = EINA_TRUE;
6838 if (!term->wn->cmdbox)
6839 {
6840 Evas_Object *o;
6841 Win *wn = term->wn;
6842
6843 wn->cmdbox = o = elm_entry_add(wn->win);
6844 elm_entry_single_line_set(o, EINA_TRUE);
6845 elm_entry_scrollable_set(o, EINA_FALSE);
6846 elm_scroller_policy_set(o, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
6847 elm_entry_input_panel_layout_set(o, ELM_INPUT_PANEL_LAYOUT_TERMINAL);
6848 elm_entry_autocapital_type_set(o, ELM_AUTOCAPITAL_TYPE_NONE);
6849 elm_entry_input_panel_enabled_set(o, EINA_TRUE);
6850 elm_entry_input_panel_language_set(o, ELM_INPUT_PANEL_LANG_ALPHABET);
6851 elm_entry_input_panel_return_key_type_set(o, ELM_INPUT_PANEL_RETURN_KEY_TYPE_GO);
6852 elm_entry_prediction_allow_set(o, EINA_FALSE);
6853 evas_object_show(o);
6854 evas_object_smart_callback_add(o, "activated", _cb_cmd_activated, wn);
6855 evas_object_smart_callback_add(o, "aborted", _cb_cmd_aborted, wn);
6856 evas_object_smart_callback_add(o, "changed,user", _cb_cmd_changed, wn);
6857 evas_object_event_callback_add(o, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
6858 _cb_cmd_hints_changed, wn);
6859 elm_layout_content_set(wn->base, "terminology.cmdbox", o);
6860 }
6861 elm_layout_signal_emit(term->wn->base, "cmdbox,show", "terminology");
6862 elm_entry_entry_set(term->wn->cmdbox, "");
6863 evas_object_show(term->wn->cmdbox);
6864 elm_object_focus_set(term->wn->cmdbox, EINA_TRUE);
6865 if (term->wn->cmdbox_del_timer)
6866 {
6867 ecore_timer_del(term->wn->cmdbox_del_timer);
6868 term->wn->cmdbox_del_timer = NULL;
6869 }
6870 }
6871
6872
6873 static void
_cb_media_del(void * data,Evas * _e EINA_UNUSED,Evas_Object * _obj EINA_UNUSED,void * _event_info EINA_UNUSED)6874 _cb_media_del(void *data,
6875 Evas *_e EINA_UNUSED,
6876 Evas_Object *_obj EINA_UNUSED,
6877 void *_event_info EINA_UNUSED)
6878 {
6879 Term *term = data;
6880 Config *config = NULL;
6881
6882 if (term->termio)
6883 config = termio_config_get(term->termio);
6884 term->media = NULL;
6885 if (term->bg)
6886 {
6887 elm_layout_signal_emit(term->bg, "media,off", "terminology");
6888 elm_layout_signal_emit(term->core, "media,off", "terminology");
6889 }
6890 if (!config) return;
6891 if (config->temporary)
6892 eina_stringshare_replace(&(config->background), NULL);
6893 }
6894
6895 static void
_term_media_update(Term * term,const Config * config)6896 _term_media_update(Term *term, const Config *config)
6897 {
6898 if ((config->background) && (config->background[0]))
6899 {
6900 Evas_Object *o;
6901 Media_Type type;
6902
6903 if (term->media)
6904 {
6905 evas_object_event_callback_del(term->media,
6906 EVAS_CALLBACK_DEL,
6907 _cb_media_del);
6908 evas_object_del(term->media);
6909 }
6910 type = media_src_type_get(config->background);
6911 term->media = o = media_add(term->wn->win,
6912 config->background, config,
6913 MEDIA_BG, type);
6914 evas_object_event_callback_add(o, EVAS_CALLBACK_DEL,
6915 _cb_media_del, term);
6916 elm_layout_content_set(term->core, "terminology.background", o);
6917 evas_object_show(o);
6918 term->mediatype = type;
6919 switch (type)
6920 {
6921 case MEDIA_TYPE_IMG:
6922 elm_layout_signal_emit(term->bg, "media,image", "terminology");
6923 elm_layout_signal_emit(term->core, "media,image", "terminology");
6924 break;
6925 case MEDIA_TYPE_SCALE:
6926 elm_layout_signal_emit(term->bg, "media,scale", "terminology");
6927 elm_layout_signal_emit(term->core, "media,scale", "terminology");
6928 break;
6929 case MEDIA_TYPE_EDJE:
6930 elm_layout_signal_emit(term->bg, "media,edje", "terminology");
6931 elm_layout_signal_emit(term->core, "media,edje", "terminology");
6932 break;
6933 case MEDIA_TYPE_MOV:
6934 elm_layout_signal_emit(term->bg, "media,movie", "terminology");
6935 elm_layout_signal_emit(term->core, "media,movie", "terminology");
6936 break;
6937 case MEDIA_TYPE_UNKNOWN:
6938 default:
6939 break;
6940 }
6941 }
6942 else
6943 {
6944 if (term->media)
6945 {
6946 evas_object_event_callback_del(term->media,
6947 EVAS_CALLBACK_DEL,
6948 _cb_media_del);
6949 elm_layout_signal_emit(term->bg, "media,off", "terminology");
6950 elm_layout_signal_emit(term->core, "media,off", "terminology");
6951 evas_object_del(term->media);
6952 term->media = NULL;
6953 }
6954 }
6955 }
6956
6957 void
main_media_update(const Config * config)6958 main_media_update(const Config *config)
6959 {
6960 Win *wn;
6961 Term *term;
6962 Eina_List *l, *ll;
6963
6964 EINA_LIST_FOREACH(wins, l, wn)
6965 {
6966 EINA_LIST_FOREACH(wn->terms, ll, term)
6967 {
6968 if (term->config != config) continue;
6969 if (!config) continue;
6970 _term_media_update(term, config);
6971 }
6972 }
6973 }
6974
6975 void
main_media_mute_update(const Config * config)6976 main_media_mute_update(const Config *config)
6977 {
6978 Win *wn;
6979 Term *term;
6980 Eina_List *l, *ll;
6981
6982 EINA_LIST_FOREACH(wins, l, wn)
6983 {
6984 EINA_LIST_FOREACH(wn->terms, ll, term)
6985 {
6986 if (term->media) media_mute_set(term->media, config->mute);
6987 termio_media_mute_set(term->termio, config->mute);
6988 }
6989 }
6990 }
6991
6992 void
main_media_visualize_update(const Config * config)6993 main_media_visualize_update(const Config *config)
6994 {
6995 Win *wn;
6996 Term *term;
6997 Eina_List *l, *ll;
6998
6999 EINA_LIST_FOREACH(wins, l, wn)
7000 {
7001 EINA_LIST_FOREACH(wn->terms, ll, term)
7002 {
7003 if (term->media) media_visualize_set(term->media, config->visualize);
7004 termio_media_visualize_set(term->termio, config->visualize);
7005 }
7006 }
7007 }
7008
7009 void
main_config_sync(const Config * config)7010 main_config_sync(const Config *config)
7011 {
7012 Win *wn;
7013 Term *term;
7014 Eina_List *l, *ll;
7015 Config *main_config = main_config_get();
7016
7017 if (config != main_config) config_sync(config, main_config);
7018 EINA_LIST_FOREACH(wins, l, wn)
7019 {
7020 if (wn->config != config) config_sync(config, wn->config);
7021 EINA_LIST_FOREACH(wn->terms, ll, term)
7022 {
7023 if (term->config != config)
7024 {
7025 Evas_Coord mw = 1, mh = 1, w, h, tsize_w = 0, tsize_h = 0;
7026
7027 config_sync(config, term->config);
7028 evas_object_geometry_get(term->termio, NULL, NULL,
7029 &tsize_w, &tsize_h);
7030 evas_object_data_del(term->termio, "sizedone");
7031 termio_config_update(term->termio);
7032 evas_object_size_hint_min_get(term->termio, &mw, &mh);
7033 if (mw < 1) mw = 1;
7034 if (mh < 1) mh = 1;
7035 w = tsize_w / mw;
7036 h = tsize_h / mh;
7037 evas_object_data_del(term->termio, "sizedone");
7038 evas_object_size_hint_request_set(term->termio,
7039 w * mw, h * mh);
7040 }
7041 }
7042 }
7043 }
7044
7045 static void
_term_free(Term * term)7046 _term_free(Term *term)
7047 {
7048 if (_tab_drag && _tab_drag->term == term)
7049 {
7050 _tab_drag_free();
7051 }
7052 if (_tab_drag && _tab_drag->term_over == term)
7053 {
7054 _tab_drag->term_over = NULL;
7055 _tab_drag->split_direction = SPLIT_DIRECTION_NONE;
7056 }
7057 if (term->sendfile_request)
7058 {
7059 evas_object_del(term->sendfile_request);
7060 term->sendfile_request = NULL;
7061 }
7062 if (term->sendfile_progress)
7063 {
7064 evas_object_del(term->sendfile_progress);
7065 term->sendfile_progress = NULL;
7066 }
7067 if (term->sendfile_request_hide_timer)
7068 {
7069 ecore_timer_del(term->sendfile_request_hide_timer);
7070 term->sendfile_request_hide_timer = NULL;
7071 }
7072 if (term->sendfile_progress_hide_timer)
7073 {
7074 ecore_timer_del(term->sendfile_progress_hide_timer);
7075 term->sendfile_progress_hide_timer = NULL;
7076 }
7077 eina_stringshare_del(term->sendfile_dir);
7078 term->sendfile_dir = NULL;
7079 _popmedia_queue_free(term);
7080 if (term->media)
7081 {
7082 evas_object_event_callback_del(term->media,
7083 EVAS_CALLBACK_DEL,
7084 _cb_media_del);
7085 evas_object_del(term->media);
7086 }
7087 term->media = NULL;
7088 if (term->popmedia) evas_object_del(term->popmedia);
7089 if (term->miniview)
7090 {
7091 evas_object_del(term->miniview);
7092 term->miniview = NULL;
7093 }
7094 term->popmedia = NULL;
7095 term->popmedia_deleted = EINA_FALSE;
7096
7097 _term_tabregion_free(term);
7098
7099 if (term->tabbar.l.box)
7100 {
7101 elm_box_unpack_all(term->tabbar.l.box);
7102 evas_object_del(term->tabbar.l.box);
7103 term->tabbar.l.box = NULL;
7104 }
7105 if (term->tabbar.r.box)
7106 {
7107 elm_box_unpack_all(term->tabbar.r.box);
7108 evas_object_del(term->tabbar.r.box);
7109 term->tabbar.r.box = NULL;
7110 }
7111
7112 evas_object_del(term->tab_inactive);
7113 term->tab_inactive = NULL;
7114 term->tab_item = NULL;
7115
7116 evas_object_del(term->termio);
7117 term->termio = NULL;
7118
7119 evas_object_del(term->core);
7120 term->core = NULL;
7121 evas_object_del(term->bg);
7122 term->bg = NULL;
7123 term->bg_edj = NULL;
7124
7125 if (term->tab_spacer)
7126 {
7127 evas_object_del(term->tab_spacer);
7128 term->tab_spacer = NULL;
7129 }
7130 free(term);
7131 }
7132
7133 static void
_cb_tab_prev(void * data,Evas_Object * _obj EINA_UNUSED,const char * _sig EINA_UNUSED,const char * _src EINA_UNUSED)7134 _cb_tab_prev(void *data,
7135 Evas_Object *_obj EINA_UNUSED,
7136 const char *_sig EINA_UNUSED,
7137 const char *_src EINA_UNUSED)
7138 {
7139 _cb_prev(data, NULL, NULL);
7140 }
7141
7142 static void
_cb_tab_next(void * data,Evas_Object * _obj EINA_UNUSED,const char * _sig EINA_UNUSED,const char * _src EINA_UNUSED)7143 _cb_tab_next(void *data,
7144 Evas_Object *_obj EINA_UNUSED,
7145 const char *_sig EINA_UNUSED,
7146 const char *_src EINA_UNUSED)
7147 {
7148 _cb_next(data, NULL, NULL);
7149 }
7150
7151
7152 static void
_term_bg_config(Term * term)7153 _term_bg_config(Term *term)
7154 {
7155 _term_trans(term);
7156 background_set_shine(term->config, term->bg_edj);
7157
7158 termio_theme_set(term->termio, term->bg_edj);
7159 elm_layout_signal_callback_add(term->bg, "popmedia,done", "terminology",
7160 _cb_popmedia_done, term);
7161 elm_layout_signal_callback_add(term->bg, "tab,go", "terminology",
7162 _cb_tab_go, term);
7163 elm_layout_signal_callback_add(term->bg, "tab,new", "terminology",
7164 _cb_tab_new, term);
7165 elm_layout_signal_callback_add(term->bg, "tab,prev", "terminology",
7166 _cb_tab_prev, term);
7167 elm_layout_signal_callback_add(term->bg, "tab,next", "terminology",
7168 _cb_tab_next, term);
7169 elm_layout_signal_callback_add(term->bg, "tab,close", "terminology",
7170 _cb_tab_close, term);
7171 elm_layout_signal_callback_add(term->bg, "tab,title", "terminology",
7172 _cb_tab_title, term);
7173 elm_layout_signal_callback_add(term->bg, "tab,hdrag", "*",
7174 _term_on_horizontal_drag, term);
7175 elm_layout_signal_callback_add(term->bg, "tab,drag,move", "*",
7176 _tabs_drag_mouse_move, term);
7177 elm_layout_signal_callback_add(term->bg, "tab,drag,stop", "*",
7178 _term_on_drag_stop, term);
7179 elm_layout_signal_callback_add(term->bg, "tab,mouse,down", "*",
7180 _tabs_mouse_down, term);
7181 elm_layout_content_set(term->core, "terminology.content", term->termio);
7182 elm_layout_content_set(term->bg, "terminology.content", term->core);
7183 elm_layout_content_set(term->bg, "terminology.miniview", term->miniview);
7184 if (term->popmedia)
7185 {
7186 elm_layout_content_set(term->bg, "terminology.popmedia", term->popmedia);
7187 switch (term->poptype)
7188 {
7189 case MEDIA_TYPE_IMG:
7190 elm_layout_signal_emit(term->bg, "popmedia,image", "terminology");
7191 break;
7192 case MEDIA_TYPE_SCALE:
7193 elm_layout_signal_emit(term->bg, "popmedia,scale", "terminology");
7194 break;
7195 case MEDIA_TYPE_EDJE:
7196 elm_layout_signal_emit(term->bg, "popmedia,edje", "terminology");
7197 break;
7198 case MEDIA_TYPE_MOV:
7199 elm_layout_signal_emit(term->bg, "popmedia,movie", "terminology");
7200 break;
7201 default:
7202 break;
7203 }
7204 }
7205 if (term->media)
7206 {
7207 elm_layout_content_set(term->core, "terminology.background", term->media);
7208 switch (term->mediatype)
7209 {
7210 case MEDIA_TYPE_IMG:
7211 elm_layout_signal_emit(term->bg, "media,image", "terminology");
7212 elm_layout_signal_emit(term->core, "media,image", "terminology");
7213 break;
7214 case MEDIA_TYPE_SCALE:
7215 elm_layout_signal_emit(term->bg, "media,scale", "terminology");
7216 elm_layout_signal_emit(term->core, "media,scale", "terminology");
7217 break;
7218 case MEDIA_TYPE_EDJE:
7219 elm_layout_signal_emit(term->bg, "media,edje", "terminology");
7220 elm_layout_signal_emit(term->core, "media,edje", "terminology");
7221 break;
7222 case MEDIA_TYPE_MOV:
7223 elm_layout_signal_emit(term->bg, "media,movie", "terminology");
7224 elm_layout_signal_emit(term->core, "media,movie", "terminology");
7225 break;
7226 case MEDIA_TYPE_UNKNOWN:
7227 default:
7228 break;
7229 }
7230 }
7231
7232 DBG("is focused? tc:%p", term->container);
7233 if (term_is_focused(term) && (_win_is_focused(term->wn)))
7234 {
7235 if (term->config->disable_focus_visuals)
7236 {
7237 elm_layout_signal_emit(term->bg, "focused,set", "terminology");
7238 elm_layout_signal_emit(term->core, "focused,set", "terminology");
7239 }
7240 else
7241 {
7242 elm_layout_signal_emit(term->bg, "focus,in", "terminology");
7243 elm_layout_signal_emit(term->core, "focus,in", "terminology");
7244 }
7245 }
7246 if (term->miniview_shown)
7247 elm_layout_signal_emit(term->bg, "miniview,on", "terminology");
7248
7249 _term_media_update(term, term->config);
7250 }
7251
7252 static void
_cb_tabregion_change(void * data,Evas * _e EINA_UNUSED,Evas_Object * obj,void * _info EINA_UNUSED)7253 _cb_tabregion_change(void *data,
7254 Evas *_e EINA_UNUSED,
7255 Evas_Object *obj,
7256 void *_info EINA_UNUSED)
7257 {
7258 Term *term = data;
7259 Evas_Coord w, h;
7260
7261 evas_object_geometry_get(obj, NULL, NULL, &w, &h);
7262 evas_object_size_hint_min_set(term->tab_region_base, w, h);
7263 elm_layout_content_set(term->core, "terminology.tabregion",
7264 term->tab_region_base);
7265 }
7266
7267 static void
_term_tabregion_setup(Term * term)7268 _term_tabregion_setup(Term *term)
7269 {
7270 Evas_Object *o;
7271
7272 if (term->tab_region_bg) return;
7273 term->tab_region_bg = o = evas_object_rectangle_add(evas_object_evas_get(term->bg));
7274 evas_object_color_set(o, 0, 0, 0, 0);
7275 evas_object_event_callback_add(o, EVAS_CALLBACK_RESIZE, _cb_tabregion_change, term);
7276 elm_layout_content_set(term->bg, "terminology.tabregion", o);
7277
7278 term->tab_region_base = o = evas_object_rectangle_add(evas_object_evas_get(term->bg));
7279 evas_object_color_set(o, 0, 0, 0, 0);
7280 elm_layout_content_set(term->core, "terminology.tabregion", o);
7281 }
7282
7283 static void
_term_tabregion_free(Term * term)7284 _term_tabregion_free(Term *term)
7285 {
7286 evas_object_del(term->tab_region_bg);
7287 term->tab_region_bg = NULL;
7288
7289 evas_object_del(term->tab_region_base);
7290 term->tab_region_base = NULL;
7291 }
7292
7293 Eina_Bool
main_term_popup_exists(const Term * term)7294 main_term_popup_exists(const Term *term)
7295 {
7296 return term->popmedia || term->popmedia_queue;
7297 }
7298
7299 Win *
term_win_get(const Term * term)7300 term_win_get(const Term *term)
7301 {
7302 return term->wn;
7303 }
7304
7305
7306 Evas_Object *
term_termio_get(const Term * term)7307 term_termio_get(const Term *term)
7308 {
7309 return term->termio;
7310 }
7311
7312 Evas_Object *
term_miniview_get(const Term * term)7313 term_miniview_get(const Term *term)
7314 {
7315 if (term)
7316 return term->miniview;
7317 return NULL;
7318 }
7319
7320 Evas_Object *
term_bg_get(const Term * term)7321 term_bg_get(const Term *term)
7322 {
7323 if (term)
7324 return term->bg_edj;
7325 return NULL;
7326 }
7327
7328
7329 static void
_cb_bell(void * data,Evas_Object * _obj EINA_UNUSED,void * _event EINA_UNUSED)7330 _cb_bell(void *data,
7331 Evas_Object *_obj EINA_UNUSED,
7332 void *_event EINA_UNUSED)
7333 {
7334 Term *term = data;
7335 Term_Container *tc;
7336
7337 tc = term->container;
7338
7339 tc->bell(tc, tc);
7340 }
7341
7342
7343 static void
_cb_options_done(void * data)7344 _cb_options_done(void *data)
7345 {
7346 Term *orig_term = data;
7347 Win *wn = orig_term->wn;
7348
7349 elm_object_focus_highlight_style_set(wn->base, "blank");
7350 _on_popover_done(wn);
7351
7352 term_unref(orig_term);
7353 }
7354
7355 static void
_cb_options(void * data,Evas_Object * _obj EINA_UNUSED,void * _event EINA_UNUSED)7356 _cb_options(void *data,
7357 Evas_Object *_obj EINA_UNUSED,
7358 void *_event EINA_UNUSED)
7359 {
7360 Term *term = data;
7361 Term_Container *tc = term->container;
7362
7363 term->wn->on_popover++;
7364
7365 term_ref(term);
7366
7367 tc->unfocus(tc, NULL);
7368
7369 elm_object_focus_highlight_style_set(term->wn->base, "default");
7370 controls_show(term->wn->win, term->wn->base, term->bg_edj, term->termio,
7371 _cb_options_done, term);
7372 }
7373
7374 void
term_ref(Term * term)7375 term_ref(Term *term)
7376 {
7377 term->refcnt++;
7378 }
7379
7380 void
term_unref(Term * term)7381 term_unref(Term *term)
7382 {
7383 EINA_SAFETY_ON_NULL_RETURN(term);
7384
7385 term->refcnt--;
7386 if (term->refcnt <= 0)
7387 {
7388 _term_free(term);
7389 }
7390 }
7391
7392
7393 Term *
term_new(Win * wn,Config * config,const char * cmd,Eina_Bool login_shell,const char * cd,int size_w,int size_h,Eina_Bool hold,const char * title)7394 term_new(Win *wn, Config *config, const char *cmd,
7395 Eina_Bool login_shell, const char *cd,
7396 int size_w, int size_h, Eina_Bool hold,
7397 const char *title)
7398 {
7399 Term *term;
7400 Evas_Object *o;
7401
7402 term = calloc(1, sizeof(Term));
7403 if (!term) return NULL;
7404 term_ref(term);
7405
7406 if (!config) abort();
7407
7408 termpty_init();
7409 miniview_init();
7410 gravatar_init();
7411
7412 term->wn = wn;
7413 term->hold = hold;
7414 term->config = config;
7415
7416 term->core = o = elm_layout_add(wn->win);
7417 theme_apply(o, term->config, "terminology/core", NULL, NULL, EINA_TRUE);
7418 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
7419 evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
7420
7421 theme_auto_reload_enable(o);
7422 evas_object_data_set(o, "theme_reload_func", _term_bg_config);
7423 evas_object_data_set(o, "theme_reload_func_data", term);
7424 evas_object_show(o);
7425
7426 term->bg = o = elm_layout_add(wn->win);
7427 term->bg_edj = elm_layout_edje_get(o);
7428 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
7429 evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
7430 if (!theme_apply(o, config, "terminology/background", NULL, NULL, EINA_TRUE))
7431 {
7432 CRITICAL(_("Couldn't find terminology theme! Forgot 'ninja install'?"));
7433 evas_object_del(term->bg);
7434 free(term);
7435 return NULL;
7436 }
7437
7438 theme_auto_reload_enable(o);
7439 evas_object_data_set(o, "theme_reload_func", _term_bg_config);
7440 evas_object_data_set(o, "theme_reload_func_data", term);
7441 evas_object_show(o);
7442
7443 _term_tabregion_setup(term);
7444
7445
7446 if (term->config->mv_always_show)
7447 term->miniview_shown = EINA_TRUE;
7448
7449 _term_trans(term);
7450
7451 background_set_shine(term->config, term->bg_edj);
7452
7453 term->termio = o = termio_add(wn->win, config, cmd, login_shell, cd,
7454 size_w, size_h, term, title);
7455 evas_object_data_set(o, "term", term);
7456 colors_term_init(termio_textgrid_get(term->termio),
7457 term->config->color_scheme);
7458
7459 termio_theme_set(o, term->bg_edj);
7460
7461 term->miniview = o = miniview_add(wn->win, term->termio);
7462 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
7463 evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
7464
7465 o = term->termio;
7466 evas_object_size_hint_weight_set(o, 0, EVAS_HINT_EXPAND);
7467 evas_object_size_hint_fill_set(o, 0, EVAS_HINT_FILL);
7468 evas_object_event_callback_add(o, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
7469 _cb_size_hint, term);
7470 elm_layout_content_set(term->core, "terminology.content", o);
7471
7472 elm_layout_content_set(term->bg, "terminology.content", term->core);
7473 elm_layout_content_set(term->bg, "terminology.miniview", term->miniview);
7474
7475 evas_object_smart_callback_add(o, "options", _cb_options, term);
7476 evas_object_smart_callback_add(o, "bell", _cb_bell, term);
7477 evas_object_smart_callback_add(o, "popup", _cb_popup, term);
7478 evas_object_smart_callback_add(o, "popup,queue", _cb_popup_queue, term);
7479 evas_object_smart_callback_add(o, "cmdbox", _cb_cmdbox, term);
7480 evas_object_smart_callback_add(o, "command", _cb_command, term);
7481 evas_object_smart_callback_add(o, "prev", _cb_prev, term);
7482 evas_object_smart_callback_add(o, "next", _cb_next, term);
7483 evas_object_smart_callback_add(o, "new", _cb_new, term);
7484 evas_object_smart_callback_add(o, "close", _cb_close, term);
7485 evas_object_smart_callback_add(o, "select", _cb_select, term);
7486 evas_object_smart_callback_add(o, "split,h", _cb_split_h, term);
7487 evas_object_smart_callback_add(o, "split,v", _cb_split_v, term);
7488 evas_object_smart_callback_add(o, "title,change", _cb_title, term);
7489 evas_object_smart_callback_add(o, "icon,change", _cb_icon, term);
7490 evas_object_smart_callback_add(o, "send,progress", _cb_send_progress, term);
7491 evas_object_smart_callback_add(o, "send,end", _cb_send_end, term);
7492 evas_object_show(o);
7493
7494 wn->terms = eina_list_append(wn->terms, term);
7495
7496 _term_bg_config(term);
7497
7498 return term;
7499 }
7500
7501
7502 /* }}} */
7503
7504 static Eina_Bool
_font_size_set(Term * term,void * data)7505 _font_size_set(Term *term, void *data)
7506 {
7507 int fontsize = (intptr_t) data;
7508
7509 termio_font_size_set(term->termio, fontsize);
7510
7511 return ECORE_CALLBACK_PASS_ON;
7512 }
7513
7514 void
win_font_size_set(Win * wn,int new_size)7515 win_font_size_set(Win *wn, int new_size)
7516 {
7517 for_each_term_do(wn, &_font_size_set, (void*)(intptr_t)new_size);
7518 }
7519
7520 static Eina_Bool
_font_update(Term * term,void * _data EINA_UNUSED)7521 _font_update(Term *term, void *_data EINA_UNUSED)
7522 {
7523 termio_font_update(term->termio);
7524
7525 return ECORE_CALLBACK_PASS_ON;
7526 }
7527
7528 void
win_font_update(Term * term)7529 win_font_update(Term *term)
7530 {
7531 Win *wn = term->wn;
7532 for_each_term_do(wn, &_font_update, NULL);
7533 }
7534
7535 void
windows_free(void)7536 windows_free(void)
7537 {
7538 Eina_List *l, *l_next;
7539 Win *wn;
7540
7541 EINA_LIST_FOREACH_SAFE(wins, l, l_next, wn)
7542 {
7543 win_free(wn);
7544 }
7545
7546 /* TODO: ugly */
7547 if (_win_log_dom < 0) return;
7548 eina_log_domain_unregister(_win_log_dom);
7549 _win_log_dom = -1;
7550 }
7551
7552 void
windows_update(void)7553 windows_update(void)
7554 {
7555 Eina_List *l;
7556 Win *wn;
7557
7558 EINA_LIST_FOREACH(wins, l, wn)
7559 {
7560 Term_Container *tc = (Term_Container *) wn;
7561 tc->update(tc);
7562 }
7563 }
7564
7565 Eina_Bool
for_each_term_do(Win * wn,For_Each_Term cb,void * data)7566 for_each_term_do(Win *wn, For_Each_Term cb, void *data)
7567 {
7568 Eina_List *l;
7569 Term *term;
7570 Eina_Bool res = ECORE_CALLBACK_DONE;
7571
7572 EINA_LIST_FOREACH(wn->terms, l, term)
7573 {
7574 res = cb(term, data);
7575 if (res == ECORE_CALLBACK_CANCEL)
7576 return res;
7577 }
7578 return res;
7579 }
7580