[WM_ROT] Fixed floating mode window rotation bug that window doesn't send ROTATION_DO...
[platform/core/uifw/e17.git] / src / bin / e_win.c
1 #include "e.h"
2
3 /* local subsystem functions */
4 static void _e_win_free(E_Win *win);
5 static void _e_win_del(void *obj);
6 static void _e_win_prop_update(E_Win *win);
7 static void _e_win_state_update(E_Win *win);
8 static void _e_win_cb_move(Ecore_Evas *ee);
9 static void _e_win_cb_resize(Ecore_Evas *ee);
10 static void _e_win_cb_delete(Ecore_Evas *ee);
11
12 /* local subsystem globals */
13 static Eina_List *wins = NULL;
14
15 #ifdef HAVE_ELEMENTARY
16 /* intercept elm_win operations so we talk directly to e_border */
17
18 #include <Elementary.h>
19
20 typedef struct _Elm_Win_Trap_Ctx
21 {
22    E_Border *border;
23    Ecore_X_Window xwin;
24    Eina_Bool centered:1;
25    Eina_Bool placed:1;
26 } Elm_Win_Trap_Ctx;
27
28 static void *
29 _elm_win_trap_add(Evas_Object *o __UNUSED__)
30 {
31    Elm_Win_Trap_Ctx *ctx = calloc(1, sizeof(Elm_Win_Trap_Ctx));
32    EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL);
33    return ctx;
34 }
35
36 static void
37 _elm_win_trap_del(void *data, Evas_Object *o __UNUSED__)
38 {
39    Elm_Win_Trap_Ctx *ctx = data;
40    EINA_SAFETY_ON_NULL_RETURN(ctx);
41    if (ctx->border)
42      {
43         e_border_hide(ctx->border, 1);
44         e_object_del(E_OBJECT(ctx->border));
45      }
46    free(ctx);
47 }
48
49 static Eina_Bool
50 _elm_win_trap_hide(void *data, Evas_Object *o __UNUSED__)
51 {
52    Elm_Win_Trap_Ctx *ctx = data;
53    EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_TRUE);
54    if (!ctx->border) return EINA_TRUE;
55    e_border_hide(ctx->border, 1);
56    return EINA_FALSE;
57 }
58
59 static Eina_Bool
60 _elm_win_trap_show(void *data, Evas_Object *o)
61 {
62    Elm_Win_Trap_Ctx *ctx = data;
63    EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_TRUE);
64    if (!ctx->border)
65      {
66         Ecore_X_Window xwin = elm_win_xwindow_get(o);
67         E_Container *con = e_util_container_window_find(xwin);
68         Evas *e = evas_object_evas_get(o);
69         Ecore_Evas *ee = ecore_evas_ecore_evas_get(e);
70
71         if (!con)
72           {
73              E_Manager *man = e_manager_current_get();
74              EINA_SAFETY_ON_NULL_RETURN_VAL(man, EINA_TRUE);
75              con = e_container_current_get(man);
76              if (!con) con = e_container_number_get(man, 0);
77              EINA_SAFETY_ON_NULL_RETURN_VAL(con, EINA_TRUE);
78           }
79
80         ctx->xwin = xwin;
81         ctx->border = e_border_new(con, xwin, 0, 1);
82         EINA_SAFETY_ON_NULL_RETURN_VAL(ctx->border, EINA_TRUE);
83         ctx->border->placed = ctx->placed;
84         ctx->border->internal = 1;
85         ctx->border->internal_ecore_evas = ee;
86      }
87    if (ctx->centered) e_border_center(ctx->border);
88    e_border_show(ctx->border);
89    return EINA_FALSE;
90 }
91
92 static Eina_Bool
93 _elm_win_trap_move(void *data, Evas_Object *o __UNUSED__, int x, int y)
94 {
95    Elm_Win_Trap_Ctx *ctx = data;
96    EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_TRUE);
97    ctx->centered = EINA_FALSE;
98    ctx->placed = EINA_TRUE;
99    if (!ctx->border) return EINA_TRUE;
100    e_border_move_without_border(ctx->border, x, y);
101    return EINA_FALSE;
102 }
103
104 static Eina_Bool
105 _elm_win_trap_resize(void *data, Evas_Object *o __UNUSED__, int w, int h)
106 {
107    Elm_Win_Trap_Ctx *ctx = data;
108    EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_TRUE);
109    ctx->centered = EINA_FALSE;
110    if (!ctx->border) return EINA_TRUE;
111    e_border_resize_without_border(ctx->border, w, h);
112    return EINA_FALSE;
113 }
114
115 static Eina_Bool
116 _elm_win_trap_center(void *data, Evas_Object *o __UNUSED__)
117 {
118    Elm_Win_Trap_Ctx *ctx = data;
119    EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_TRUE);
120    ctx->centered = EINA_TRUE;
121    if (!ctx->border) return EINA_TRUE;
122    if (ctx->centered) e_border_center(ctx->border);
123    return EINA_FALSE;
124 }
125
126 static Eina_Bool
127 _elm_win_trap_lower(void *data, Evas_Object *o __UNUSED__)
128 {
129    Elm_Win_Trap_Ctx *ctx = data;
130    EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_TRUE);
131    if (!ctx->border) return EINA_TRUE;
132    e_border_lower(ctx->border);
133    return EINA_FALSE;
134 }
135
136 static Eina_Bool
137 _elm_win_trap_raise(void *data, Evas_Object *o __UNUSED__)
138 {
139    Elm_Win_Trap_Ctx *ctx = data;
140    EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_TRUE);
141    if (!ctx->border) return EINA_TRUE;
142    e_border_raise(ctx->border);
143    return EINA_FALSE;
144 }
145
146 static const Elm_Win_Trap _elm_win_trap = {
147   ELM_WIN_TRAP_VERSION,
148   _elm_win_trap_add,
149   _elm_win_trap_del,
150   _elm_win_trap_hide,
151   _elm_win_trap_show,
152   _elm_win_trap_move,
153   _elm_win_trap_resize,
154   _elm_win_trap_center,
155   _elm_win_trap_lower,
156   _elm_win_trap_raise,
157   /* activate */ NULL,
158   /* alpha_set */ NULL,
159   /* aspect_set */ NULL,
160   /* avoid_damage_set */ NULL,
161   /* borderless_set */ NULL,
162   /* demand_attention_set */ NULL,
163   /* focus_skip_set */ NULL,
164   /* fullscreen_set */ NULL,
165   /* iconified_set */ NULL,
166   /* layer_set */ NULL,
167   /* manual_render_set */ NULL,
168   /* maximized_set */ NULL,
169   /* modal_set */ NULL,
170   /* name_class_set */ NULL,
171   /* object_cursor_set */ NULL,
172   /* override_set */ NULL,
173   /* rotation_set */ NULL,
174   /* rotation_with_resize_set */ NULL,
175   /* shaped_set */ NULL,
176   /* size_base_set */ NULL,
177   /* size_step_set */ NULL,
178   /* size_min_set */ NULL,
179   /* size_max_set */ NULL,
180   /* sticky_set */ NULL,
181   /* title_set */ NULL,
182   /* urgent_set */ NULL,
183   /* withdrawn_set */ NULL
184   };
185 #endif
186
187 /* externally accessible functions */
188 EINTERN int
189 e_win_init(void)
190 {
191 #ifdef HAVE_ELEMENTARY
192    if (!elm_win_trap_set(&_elm_win_trap)) return 0;
193 #endif
194    return 1;
195 }
196
197 EINTERN int
198 e_win_shutdown(void)
199 {
200 /*
201    while (wins)
202      {
203         e_object_del(E_OBJECT(wins->data));
204      }
205  */
206    return 1;
207 }
208
209 EAPI E_Win *
210 e_win_new(E_Container *con)
211 {
212    E_Win *win;
213    Evas_Object *obj;
214
215    win = E_OBJECT_ALLOC(E_Win, E_WIN_TYPE, _e_win_free);
216    if (!win) return NULL;
217    e_object_del_func_set(E_OBJECT(win), _e_win_del);
218    win->container = con;
219    win->ecore_evas = e_canvas_new(con->manager->root,
220                                   0, 0, 1, 1, 1, 0,
221                                   &(win->evas_win));
222    e_canvas_add(win->ecore_evas);
223    ecore_evas_data_set(win->ecore_evas, "E_Win", win);
224    ecore_evas_callback_move_set(win->ecore_evas, _e_win_cb_move);
225    ecore_evas_callback_resize_set(win->ecore_evas, _e_win_cb_resize);
226    ecore_evas_callback_delete_request_set(win->ecore_evas, _e_win_cb_delete);
227    win->evas = ecore_evas_get(win->ecore_evas);
228    ecore_evas_name_class_set(win->ecore_evas, "E", "_e_internal_window");
229    ecore_evas_title_set(win->ecore_evas, "E");
230    obj = evas_object_rectangle_add(win->evas);
231    evas_object_name_set(obj, "E_Win");
232    evas_object_data_set(obj, "E_Win", win);
233    win->x = 0;
234    win->y = 0;
235    win->w = 1;
236    win->h = 1;
237    win->placed = 0;
238    win->min_w = 0;
239    win->min_h = 0;
240    win->max_w = 9999;
241    win->max_h = 9999;
242    win->base_w = 0;
243    win->base_h = 0;
244    win->step_x = 1;
245    win->step_y = 1;
246    win->min_aspect = 0.0;
247    win->max_aspect = 0.0;
248    wins = eina_list_append(wins, win);
249
250    win->pointer = e_pointer_window_new(win->evas_win, 0);
251    return win;
252 }
253
254 EAPI void
255 e_win_show(E_Win *win)
256 {
257    E_OBJECT_CHECK(win);
258    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
259    if (!win->border)
260      {
261         _e_win_prop_update(win);
262         ecore_evas_lower(win->ecore_evas);
263         win->border = e_border_new(win->container, win->evas_win, 1, 1);
264 // dont need this - special stuff
265 //        win->border->ignore_first_unmap = 1;
266         if (!win->placed)
267           win->border->re_manage = 0;
268         win->border->internal = 1;
269         win->border->internal_ecore_evas = win->ecore_evas;
270         if (win->state.no_remember) win->border->internal_no_remember = 1;
271      }
272    _e_win_prop_update(win);
273    e_border_show(win->border);
274 // done now by e_border specially
275 //   ecore_evas_show(win->ecore_evas);
276 }
277
278 EAPI void
279 e_win_hide(E_Win *win)
280 {
281    E_OBJECT_CHECK(win);
282    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
283    if (win->border) e_border_hide(win->border, 1);
284 }
285
286 /**
287  * This will move window to position, automatically accounts border decorations.
288  *
289  * Don't need to account win->border->client_inset, it's done
290  * automatically, so it will work fine with new windows that still
291  * don't have the border.
292  *
293  * @parm x horizontal position to place window.
294  * @parm y vertical position to place window.
295  */
296 EAPI void
297 e_win_move(E_Win *win, int x, int y)
298 {
299    E_OBJECT_CHECK(win);
300    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
301    if (win->border)
302      e_border_move_without_border(win->border, x, y);
303    else
304      ecore_evas_move(win->ecore_evas, x, y);
305 }
306
307 /**
308  * This will resize window, automatically accounts border decorations.
309  *
310  * Don't need to account win->border->client_inset, it's done
311  * automatically, so it will work fine with new windows that still
312  * don't have the border.
313  *
314  * @parm w horizontal window size.
315  * @parm h vertical window size.
316  */
317 EAPI void
318 e_win_resize(E_Win *win, int w, int h)
319 {
320    E_OBJECT_CHECK(win);
321    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
322    if (win->border)
323      e_border_resize_without_border(win->border, w, h);
324    else
325      ecore_evas_resize(win->ecore_evas, w, h);
326 }
327
328 /**
329  * This will move and resize window to position, automatically
330  * accounts border decorations.
331  *
332  * Don't need to account win->border->client_inset, it's done
333  * automatically, so it will work fine with new windows that still
334  * don't have the border.
335  *
336  * @parm x horizontal position to place window.
337  * @parm y vertical position to place window.
338  * @parm w horizontal window size.
339  * @parm h vertical window size.
340  */
341 EAPI void
342 e_win_move_resize(E_Win *win, int x, int y, int w, int h)
343 {
344    E_OBJECT_CHECK(win);
345    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
346    if (win->border)
347      e_border_move_resize_without_border(win->border, x, y, w, h);
348    else
349      ecore_evas_move_resize(win->ecore_evas, x, y, w, h);
350 }
351
352 EAPI void
353 e_win_raise(E_Win *win)
354 {
355    E_OBJECT_CHECK(win);
356    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
357    if (win->border)
358      e_border_raise(win->border);
359 }
360
361 EAPI void
362 e_win_lower(E_Win *win)
363 {
364    E_OBJECT_CHECK(win);
365    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
366    if (win->border)
367      e_border_lower(win->border);
368 }
369
370 EAPI void
371 e_win_placed_set(E_Win *win, int placed)
372 {
373    E_OBJECT_CHECK(win);
374    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
375    win->placed = placed;
376    if (win->border)
377      _e_win_prop_update(win);
378 }
379
380 EAPI Evas *
381 e_win_evas_get(E_Win *win)
382 {
383    E_OBJECT_CHECK_RETURN(win, NULL);
384    E_OBJECT_TYPE_CHECK_RETURN(win, E_WIN_TYPE, NULL);
385    return win->evas;
386 }
387
388 EAPI void
389 e_win_move_callback_set(E_Win *win, void (*func)(E_Win *win))
390 {
391    E_OBJECT_CHECK(win);
392    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
393    win->cb_move = func;
394 }
395
396 EAPI void
397 e_win_resize_callback_set(E_Win *win, void (*func)(E_Win *win))
398 {
399    E_OBJECT_CHECK(win);
400    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
401    win->cb_resize = func;
402 }
403
404 EAPI void
405 e_win_delete_callback_set(E_Win *win, void (*func)(E_Win *win))
406 {
407    E_OBJECT_CHECK(win);
408    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
409    win->cb_delete = func;
410 }
411
412 EAPI void
413 e_win_shaped_set(E_Win *win, int shaped)
414 {
415    E_OBJECT_CHECK(win);
416    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
417    ecore_evas_shaped_set(win->ecore_evas, shaped);
418 }
419
420 EAPI void
421 e_win_avoid_damage_set(E_Win *win, int avoid)
422 {
423    E_OBJECT_CHECK(win);
424    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
425    ecore_evas_avoid_damage_set(win->ecore_evas, avoid);
426 }
427
428 EAPI void
429 e_win_borderless_set(E_Win *win, int borderless)
430 {
431    E_OBJECT_CHECK(win);
432    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
433    ecore_evas_borderless_set(win->ecore_evas, borderless);
434 }
435
436 EAPI void
437 e_win_layer_set(E_Win *win, int layer)
438 {
439    E_OBJECT_CHECK(win);
440    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
441    ecore_evas_layer_set(win->ecore_evas, layer);
442 }
443
444 EAPI void
445 e_win_sticky_set(E_Win *win, int sticky)
446 {
447    E_OBJECT_CHECK(win);
448    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
449    ecore_evas_sticky_set(win->ecore_evas, sticky);
450 }
451
452 EAPI void
453 e_win_size_min_set(E_Win *win, int w, int h)
454 {
455    E_OBJECT_CHECK(win);
456    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
457    win->min_w = w;
458    win->min_h = h;
459    if (win->border)
460      _e_win_prop_update(win);
461 }
462
463 EAPI void
464 e_win_size_max_set(E_Win *win, int w, int h)
465 {
466    E_OBJECT_CHECK(win);
467    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
468    win->max_w = w;
469    win->max_h = h;
470    if (win->border)
471      _e_win_prop_update(win);
472 }
473
474 EAPI void
475 e_win_size_base_set(E_Win *win, int w, int h)
476 {
477    E_OBJECT_CHECK(win);
478    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
479    win->base_w = w;
480    win->base_h = h;
481    if (win->border)
482      _e_win_prop_update(win);
483 }
484
485 EAPI void
486 e_win_step_set(E_Win *win, int x, int y)
487 {
488    E_OBJECT_CHECK(win);
489    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
490    win->step_x = x;
491    win->step_y = y;
492    if (win->border)
493      _e_win_prop_update(win);
494 }
495
496 EAPI void
497 e_win_name_class_set(E_Win *win, const char *name, const char *class)
498 {
499    E_OBJECT_CHECK(win);
500    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
501    ecore_evas_name_class_set(win->ecore_evas, name, class);
502 }
503
504 EAPI void
505 e_win_title_set(E_Win *win, const char *title)
506 {
507    E_OBJECT_CHECK(win);
508    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
509    ecore_evas_title_set(win->ecore_evas, title);
510 }
511
512 EAPI void
513 e_win_centered_set(E_Win *win, int centered)
514 {
515    E_OBJECT_CHECK(win);
516    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
517    if ((win->state.centered) && (!centered))
518      {
519         win->state.centered = 0;
520         _e_win_state_update(win);
521      }
522    else if ((!win->state.centered) && (centered))
523      {
524         win->state.centered = 1;
525         _e_win_state_update(win);
526      }
527    if ((win->border) && (centered))
528      e_border_center(win->border);
529 }
530
531 EAPI void
532 e_win_dialog_set(E_Win *win, int dialog)
533 {
534    E_OBJECT_CHECK(win);
535    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
536    if ((win->state.dialog) && (!dialog))
537      {
538         win->state.dialog = 0;
539         _e_win_prop_update(win);
540      }
541    else if ((!win->state.dialog) && (dialog))
542      {
543         win->state.dialog = 1;
544         _e_win_prop_update(win);
545      }
546 }
547
548 EAPI void
549 e_win_no_remember_set(E_Win *win, int no_remember)
550 {
551    E_OBJECT_CHECK(win);
552    E_OBJECT_TYPE_CHECK(win, E_WIN_TYPE);
553    win->state.no_remember = no_remember;
554 }
555
556 EAPI E_Win *
557 e_win_evas_object_win_get(Evas_Object *obj)
558 {
559    Evas *evas;
560    Evas_Object *wobj;
561    E_Win *win;
562
563    if (!obj) return NULL;
564    evas = evas_object_evas_get(obj);
565    wobj = evas_object_name_find(evas, "E_Win");
566    if (!wobj) return NULL;
567    win = evas_object_data_get(wobj, "E_Win");
568    return win;
569 }
570
571 EAPI void
572 e_win_border_icon_set(E_Win *win, const char *icon)
573 {
574    E_Border *border;
575
576    border = win->border;
577    if (!border) return;
578    if (border->internal_icon)
579      {
580         eina_stringshare_del(border->internal_icon);
581         border->internal_icon = NULL;
582      }
583    if (icon)
584      border->internal_icon = eina_stringshare_add(icon);
585 }
586
587 EAPI void
588 e_win_border_icon_key_set(E_Win *win, const char *key)
589 {
590    E_Border *border;
591
592    border = win->border;
593    if (!border) return;
594    if (border->internal_icon_key)
595      {
596         eina_stringshare_del(border->internal_icon_key);
597         border->internal_icon_key = NULL;
598      }
599    if (key)
600      border->internal_icon_key = eina_stringshare_add(key);
601 }
602
603 /* local subsystem functions */
604 static void
605 _e_win_free(E_Win *win)
606 {
607    if (win->pointer)
608      e_object_del(E_OBJECT(win->pointer));
609
610    e_canvas_del(win->ecore_evas);
611    ecore_evas_free(win->ecore_evas);
612    if (win->border)
613      {
614         e_border_hide(win->border, 1);
615         e_object_del(E_OBJECT(win->border));
616      }
617    wins = eina_list_remove(wins, win);
618    free(win);
619 }
620
621 static void
622 _e_win_del(void *obj)
623 {
624    E_Win *win;
625
626    win = obj;
627    if (win->border) e_border_hide(win->border, 1);
628 }
629
630 static void
631 _e_win_prop_update(E_Win *win)
632 {
633    ecore_x_icccm_size_pos_hints_set(win->evas_win,
634                                     win->placed, ECORE_X_GRAVITY_NW,
635                                     win->min_w, win->min_h,
636                                     win->max_w, win->max_h,
637                                     win->base_w, win->base_h,
638                                     win->step_x, win->step_y,
639                                     win->min_aspect, win->max_aspect);
640    if (win->state.dialog)
641      {
642         ecore_x_icccm_transient_for_set(win->evas_win, win->container->manager->root);
643         ecore_x_netwm_window_type_set(win->evas_win, ECORE_X_WINDOW_TYPE_DIALOG);
644      }
645    else
646      {
647         ecore_x_icccm_transient_for_unset(win->evas_win);
648         ecore_x_netwm_window_type_set(win->evas_win, ECORE_X_WINDOW_TYPE_NORMAL);
649      }
650 }
651
652 static void
653 _e_win_state_update(E_Win *win)
654 {
655    Ecore_X_Atom state[1];
656    int num = 0;
657
658    if (win->state.centered)
659      state[num++] = E_ATOM_WINDOW_STATE_CENTERED;
660
661    if (num)
662      ecore_x_window_prop_card32_set(win->evas_win, E_ATOM_WINDOW_STATE, state, num);
663    else
664      ecore_x_window_prop_property_del(win->evas_win, E_ATOM_WINDOW_STATE);
665 }
666
667 static void
668 _e_win_cb_move(Ecore_Evas *ee)
669 {
670    E_Win *win;
671
672    win = ecore_evas_data_get(ee, "E_Win");
673    if (!win) return;
674    ecore_evas_geometry_get(win->ecore_evas, &win->x, &win->y, &win->w, &win->h);
675    if (win->cb_move) win->cb_move(win);
676 }
677
678 static void
679 _e_win_cb_resize(Ecore_Evas *ee)
680 {
681    E_Win *win;
682
683    win = ecore_evas_data_get(ee, "E_Win");
684    if (!win) return;
685    ecore_evas_geometry_get(win->ecore_evas, &win->x, &win->y, &win->w, &win->h);
686    if (win->cb_resize) win->cb_resize(win);
687 }
688
689 static void
690 _e_win_cb_delete(Ecore_Evas *ee)
691 {
692    E_Win *win;
693
694    win = ecore_evas_data_get(ee, "E_Win");
695    if (!win) return;
696    if (win->cb_delete) win->cb_delete(win);
697 }
698