1 #include "e.h"
2
3 static int _e_client_hooks_delete = 0;
4 static int _e_client_hooks_walking = 0;
5
6 E_API int E_EVENT_CLIENT_ADD = -1;
7 E_API int E_EVENT_CLIENT_REMOVE = -1;
8 E_API int E_EVENT_CLIENT_ZONE_SET = -1;
9 E_API int E_EVENT_CLIENT_DESK_SET = -1;
10 E_API int E_EVENT_CLIENT_RESIZE = -1;
11 E_API int E_EVENT_CLIENT_MOVE = -1;
12 E_API int E_EVENT_CLIENT_SHOW = -1;
13 E_API int E_EVENT_CLIENT_HIDE = -1;
14 E_API int E_EVENT_CLIENT_ICONIFY = -1;
15 E_API int E_EVENT_CLIENT_UNICONIFY = -1;
16 E_API int E_EVENT_CLIENT_STACK = -1;
17 E_API int E_EVENT_CLIENT_FOCUS_IN = -1;
18 E_API int E_EVENT_CLIENT_FOCUS_OUT = -1;
19 E_API int E_EVENT_CLIENT_PROPERTY = -1;
20 E_API int E_EVENT_CLIENT_FULLSCREEN = -1;
21 E_API int E_EVENT_CLIENT_UNFULLSCREEN = -1;
22
23 static Eina_Hash *clients_hash[2] = {NULL}; // pixmap->client
24
25 static unsigned int focus_track_frozen = 0;
26
27 static int warp_to = 0;
28 static int warp_to_x = 0;
29 static int warp_to_y = 0;
30 static int warp_x[2] = {0}; //{cur,prev}
31 static int warp_y[2] = {0}; //{cur,prev}
32 static Ecore_Timer *warp_timer = NULL;
33
34 static E_Client *focused = NULL;
35 static E_Client *warp_client = NULL;
36 static E_Client *ecmove = NULL;
37 static E_Client *ecresize = NULL;
38 static E_Client *action_client = NULL;
39 static E_Drag *client_drag = NULL;
40
41 static Eina_List *focus_stack = NULL;
42 static Eina_List *raise_stack = NULL;
43
44 static Eina_Bool comp_grabbed = EINA_FALSE;
45 static Evas_Object *action_rect;
46
47 static Eina_List *handlers = NULL;
48 //static Eina_Bool client_grabbed = EINA_FALSE;
49
50 static Ecore_Event_Handler *action_handler_key = NULL;
51 static Ecore_Event_Handler *action_handler_mouse = NULL;
52 static Ecore_Timer *action_timer = NULL;
53 static Eina_Rectangle action_orig = {0, 0, 0, 0};
54
55 static E_Client_Layout_Cb _e_client_layout_cb = NULL;
56
57 EINTERN void e_client_focused_set(E_Client *ec);
58
59 static Eina_Inlist *_e_client_hooks[E_CLIENT_HOOK_LAST] = {NULL};
60
61 ///////////////////////////////////////////
62
63 static Eina_Bool
_e_client_cb_efreet_cache_update(void * data EINA_UNUSED,int type EINA_UNUSED,void * ev EINA_UNUSED)64 _e_client_cb_efreet_cache_update(void *data EINA_UNUSED, int type EINA_UNUSED, void *ev EINA_UNUSED)
65 {
66 const Eina_List *l;
67 E_Client *ec;
68
69 /* mark all clients for desktop/icon updates */
70 EINA_LIST_FOREACH(e_comp->clients, l, ec)
71 {
72 E_FREE_FUNC(ec->desktop, efreet_desktop_free);
73 if (e_object_is_del(E_OBJECT(ec))) continue;
74 ec->changes.icon = 1;
75 EC_CHANGED(ec);
76 }
77 return ECORE_CALLBACK_RENEW;
78 }
79
80 static Eina_Bool
_e_client_cb_config_icon_theme(void * data EINA_UNUSED,int type EINA_UNUSED,void * ev EINA_UNUSED)81 _e_client_cb_config_icon_theme(void *data EINA_UNUSED, int type EINA_UNUSED, void *ev EINA_UNUSED)
82 {
83 const Eina_List *l;
84 E_Client *ec;
85
86 /* mark all clients for desktop/icon updates */
87 EINA_LIST_FOREACH(e_comp->clients, l, ec)
88 {
89 if (e_object_is_del(E_OBJECT(ec))) continue;
90 ec->changes.icon = 1;
91 EC_CHANGED(ec);
92 }
93 return ECORE_CALLBACK_RENEW;
94 }
95
96 static Eina_Bool
_e_client_cb_config_mode(void * data EINA_UNUSED,int type EINA_UNUSED,void * ev EINA_UNUSED)97 _e_client_cb_config_mode(void *data EINA_UNUSED, int type EINA_UNUSED, void *ev EINA_UNUSED)
98 {
99 const Eina_List *l;
100 E_Client *ec;
101 E_Layer layer;
102
103 /* move fullscreen borders above everything */
104
105 if (e_config->mode.presentation)
106 layer = E_LAYER_CLIENT_TOP;
107 else if (!e_config->allow_above_fullscreen)
108 layer = E_LAYER_CLIENT_FULLSCREEN;
109 else
110 return ECORE_CALLBACK_RENEW;
111
112 EINA_LIST_FOREACH(e_comp->clients, l, ec)
113 {
114 if (e_object_is_del(E_OBJECT(ec))) continue;
115 if ((ec->fullscreen) || (ec->need_fullscreen))
116 {
117 ec->fullscreen = 0;
118 evas_object_layer_set(ec->frame, layer);
119 ec->fullscreen = 1;
120 }
121 }
122 return ECORE_CALLBACK_PASS_ON;
123 }
124
125 static Eina_Bool
_e_client_cb_pointer_warp(void * data EINA_UNUSED,int type EINA_UNUSED,E_Event_Pointer_Warp * ev)126 _e_client_cb_pointer_warp(void *data EINA_UNUSED, int type EINA_UNUSED, E_Event_Pointer_Warp *ev)
127 {
128 if (ecmove)
129 evas_object_move(ecmove->frame, ecmove->x + (ev->curr.x - ev->prev.x), ecmove->y + (ev->curr.y - ev->prev.y));
130 return ECORE_CALLBACK_RENEW;
131 }
132
133
134 static Eina_Bool
_e_client_cb_desk_window_profile_change(void * data EINA_UNUSED,int type EINA_UNUSED,E_Event_Desk_Window_Profile_Change * ev EINA_UNUSED)135 _e_client_cb_desk_window_profile_change(void *data EINA_UNUSED, int type EINA_UNUSED, E_Event_Desk_Window_Profile_Change *ev EINA_UNUSED)
136 {
137 const Eina_List *l;
138 E_Client *ec;
139
140 EINA_LIST_FOREACH(e_comp->clients, l, ec)
141 {
142 if (e_object_is_del(E_OBJECT(ec))) continue;
143 ec->e.fetch.profile = 1;
144 EC_CHANGED(ec);
145 }
146 return ECORE_CALLBACK_RENEW;
147 }
148
149 static void
_e_client_cb_drag_finished(E_Drag * drag,int dropped EINA_UNUSED)150 _e_client_cb_drag_finished(E_Drag *drag, int dropped EINA_UNUSED)
151 {
152 E_Client *ec;
153
154 ec = drag->data;
155 UNREFD(ec, 1);
156 e_object_unref(E_OBJECT(ec));
157 client_drag = NULL;
158 }
159
160 static void
_e_client_desk_window_profile_wait_desk_delfn(void * data,void * obj)161 _e_client_desk_window_profile_wait_desk_delfn(void *data, void *obj)
162 {
163 E_Client *ec = data;
164 E_Desk *desk = obj, *new_desk;
165 const char *p;
166 int i;
167
168 if (e_object_is_del(E_OBJECT(ec))) return;
169
170 ec->e.state.profile.wait_desk_delfn = NULL;
171 eina_stringshare_replace(&ec->e.state.profile.wait, NULL);
172 if (ec->e.state.profile.wait_desk)
173 e_object_unref(E_OBJECT(ec->e.state.profile.wait_desk));
174 ec->e.state.profile.wait_desk = NULL;
175 ec->e.state.profile.wait_for_done = 0;
176
177 if (!ec->e.state.profile.use) return;
178
179 new_desk = e_comp_desk_window_profile_get(desk->window_profile);
180 if (new_desk)
181 e_client_desk_set(ec, new_desk);
182 else
183 {
184 for (i = 0; i < ec->e.state.profile.num; i++)
185 {
186 p = ec->e.state.profile.available_list[i];
187 new_desk = e_comp_desk_window_profile_get(p);
188 if (new_desk)
189 {
190 e_client_desk_set(ec, new_desk);
191 break;
192 }
193 }
194 }
195 }
196 ////////////////////////////////////////////////
197
198
199 static Eina_Bool
_e_client_pointer_warp_to_center_timer(void * data EINA_UNUSED)200 _e_client_pointer_warp_to_center_timer(void *data EINA_UNUSED)
201 {
202 if (warp_to && warp_client)
203 {
204 int x, y;
205 double spd;
206
207 ecore_evas_pointer_xy_get(e_comp->ee, &x, &y);
208 /* move hasn't happened yet */
209 if ((x == warp_x[1]) && (y == warp_y[1]))
210 return EINA_TRUE;
211 if ((abs(x - warp_x[0]) > 5) || (abs(y - warp_y[0]) > 5))
212 {
213 /* User moved the mouse, so stop warping */
214 warp_to = 0;
215 goto cleanup;
216 }
217
218 spd = e_config->pointer_warp_speed;
219 warp_x[1] = x = warp_x[0];
220 warp_y[1] = y = warp_y[0];
221 warp_x[0] = (x * (1.0 - spd)) + (warp_to_x * spd);
222 warp_y[0] = (y * (1.0 - spd)) + (warp_to_y * spd);
223 if ((warp_x[0] == x) && (warp_y[0] == y))
224 {
225 warp_x[0] = warp_to_x;
226 warp_y[0] = warp_to_y;
227 warp_to = 0;
228 goto cleanup;
229 }
230 ecore_evas_pointer_warp(e_comp->ee, warp_x[0], warp_y[0]);
231 return ECORE_CALLBACK_RENEW;
232 }
233 cleanup:
234 E_FREE_FUNC(warp_timer, ecore_timer_del);
235 if (warp_client)
236 {
237 warp_x[0] = warp_x[1] = warp_y[0] = warp_y[1] = -1;
238 if (warp_client->modal)
239 {
240 warp_client = NULL;
241 return ECORE_CALLBACK_CANCEL;
242 }
243 e_focus_event_mouse_in(warp_client);
244 if (warp_client->iconic)
245 {
246 if (!warp_client->lock_user_iconify)
247 e_client_uniconify(warp_client);
248 }
249 if (warp_client->shaded)
250 {
251 if (!warp_client->lock_user_shade)
252 e_client_unshade(warp_client, warp_client->shade_dir);
253 }
254
255 if (!warp_client->lock_focus_out)
256 {
257 evas_object_focus_set(warp_client->frame, 1);
258 e_client_focus_latest_set(warp_client);
259 }
260 warp_client = NULL;
261 }
262 return ECORE_CALLBACK_CANCEL;
263 }
264
265 ////////////////////////////////////////////////
266
267 static void
_e_client_hooks_clean(void)268 _e_client_hooks_clean(void)
269 {
270 Eina_Inlist *l;
271 E_Client_Hook *ch;
272 unsigned int x;
273
274 for (x = 0; x < E_CLIENT_HOOK_LAST; x++)
275 EINA_INLIST_FOREACH_SAFE(_e_client_hooks[x], l, ch)
276 {
277 if (!ch->delete_me) continue;
278 _e_client_hooks[x] = eina_inlist_remove(_e_client_hooks[x], EINA_INLIST_GET(ch));
279 free(ch);
280 }
281 }
282
283 static Eina_Bool
_e_client_hook_call(E_Client_Hook_Point hookpoint,E_Client * ec)284 _e_client_hook_call(E_Client_Hook_Point hookpoint, E_Client *ec)
285 {
286 E_Client_Hook *ch;
287
288 e_object_ref(E_OBJECT(ec));
289 _e_client_hooks_walking++;
290 EINA_INLIST_FOREACH(_e_client_hooks[hookpoint], ch)
291 {
292 if (ch->delete_me) continue;
293 ch->func(ch->data, ec);
294 if ((hookpoint != E_CLIENT_HOOK_DEL) &&
295 (hookpoint != E_CLIENT_HOOK_MOVE_END) &&
296 (hookpoint != E_CLIENT_HOOK_RESIZE_END) &&
297 (hookpoint != E_CLIENT_HOOK_FOCUS_UNSET) &&
298 e_object_is_del(E_OBJECT(ec)))
299 break;
300 }
301 _e_client_hooks_walking--;
302 if ((_e_client_hooks_walking == 0) && (_e_client_hooks_delete > 0))
303 _e_client_hooks_clean();
304 return !!e_object_unref(E_OBJECT(ec));
305 }
306
307 ///////////////////////////////////////////
308
309 static void
_e_client_event_simple_free(void * d EINA_UNUSED,E_Event_Client * ev)310 _e_client_event_simple_free(void *d EINA_UNUSED, E_Event_Client *ev)
311 {
312 UNREFD(ev->ec, 3);
313 e_object_unref(E_OBJECT(ev->ec));
314 free(ev);
315 }
316
317 static void
_e_client_event_simple(E_Client * ec,int type)318 _e_client_event_simple(E_Client *ec, int type)
319 {
320 E_Event_Client *ev;
321
322 ev = E_NEW(E_Event_Client, 1);
323 ev->ec = ec;
324 REFD(ec, 3);
325 e_object_ref(E_OBJECT(ec));
326 ecore_event_add(type, ev, (Ecore_End_Cb)_e_client_event_simple_free, NULL);
327 }
328
329 static void
_e_client_event_property(E_Client * ec,int prop)330 _e_client_event_property(E_Client *ec, int prop)
331 {
332 E_Event_Client_Property *ev;
333
334 ev = E_NEW(E_Event_Client_Property, 1);
335 ev->ec = ec;
336 ev->property = prop;
337 REFD(ec, 33);
338 e_object_ref(E_OBJECT(ec));
339 ecore_event_add(E_EVENT_CLIENT_PROPERTY, ev, (Ecore_End_Cb)_e_client_event_simple_free, NULL);
340 }
341
342 static void
_e_client_event_desk_set_free(void * d EINA_UNUSED,E_Event_Client_Desk_Set * ev)343 _e_client_event_desk_set_free(void *d EINA_UNUSED, E_Event_Client_Desk_Set *ev)
344 {
345 UNREFD(ev->ec, 4);
346 e_object_unref(E_OBJECT(ev->ec));
347 e_object_unref(E_OBJECT(ev->desk));
348 free(ev);
349 }
350
351 static void
_e_client_event_zone_set_free(void * d EINA_UNUSED,E_Event_Client_Zone_Set * ev)352 _e_client_event_zone_set_free(void *d EINA_UNUSED, E_Event_Client_Zone_Set *ev)
353 {
354 UNREFD(ev->ec, 5);
355 e_object_unref(E_OBJECT(ev->ec));
356 e_object_unref(E_OBJECT(ev->zone));
357 free(ev);
358 }
359
360 ////////////////////////////////////////////////
361
362 static int
_e_client_action_input_win_del(void)363 _e_client_action_input_win_del(void)
364 {
365 if (!comp_grabbed) return 0;
366
367 comp_grabbed = 0;
368 E_FREE_FUNC(action_rect, evas_object_del);
369 e_comp_shape_queue();
370 e_comp_ungrab_input(1, 1);
371 return 1;
372 }
373
374 static void
_e_client_action_finish(void)375 _e_client_action_finish(void)
376 {
377 if (comp_grabbed)
378 _e_client_action_input_win_del();
379
380 if (action_handler_key && action_client)
381 evas_object_freeze_events_set(action_client->frame, 0);
382 E_FREE_FUNC(action_timer, ecore_timer_del);
383 E_FREE_FUNC(action_handler_key, ecore_event_handler_del);
384 E_FREE_FUNC(action_handler_mouse, ecore_event_handler_del);
385 if (action_client)
386 {
387 action_client->keyboard_resizing = 0;
388 if (action_client->internal_elm_win)
389 ecore_event_window_ignore_events(elm_win_window_id_get(action_client->internal_elm_win), 0);
390 }
391 action_client = NULL;
392 }
393
394 static void
_e_client_mouse_action_end(E_Client * ec)395 _e_client_mouse_action_end(E_Client *ec)
396 {
397 if (!ec->cur_mouse_action) return;
398 if (ec->cur_mouse_action->func.end_mouse)
399 ec->cur_mouse_action->func.end_mouse(E_OBJECT(ec), "", NULL);
400 else if (ec->cur_mouse_action->func.end)
401 ec->cur_mouse_action->func.end(E_OBJECT(ec), "");
402 E_FREE_FUNC(ec->cur_mouse_action, e_object_unref);
403 }
404
405 static void
_e_client_revert_focus(E_Client * ec)406 _e_client_revert_focus(E_Client *ec)
407 {
408 E_Client *pec;
409 E_Desk *desk;
410
411 if (stopping) return;
412
413 if (!ec->focused) return;
414 if (!ec->zone) return;
415
416 desk = e_desk_current_get(ec->zone);
417 if (ec->desk == desk)
418 evas_object_focus_set(ec->frame, 0);
419
420 if (ec->stack.prev)
421 {
422 ec->stack.focus_skip = 1;
423 pec = e_client_stack_active_adjust(ec);
424 ec->stack.focus_skip = 0;
425 if ((pec != ec) && (!pec->iconic))
426 evas_object_focus_set(pec->frame, 1);
427 else
428 {
429 if ((e_object_is_del(E_OBJECT(ec))) || (ec->iconic))
430 {
431 Eina_Bool unlock = ec->lock_focus_out;
432 ec->lock_focus_out = 1;
433 pec = e_desk_last_focused_focus(desk);
434 ec->lock_focus_out = unlock;
435 }
436 }
437 }
438 else if ((ec->parent) &&
439 (ec->parent->desk == desk) && (ec->parent->modal == ec))
440 {
441 evas_object_focus_set(ec->parent->frame, 1);
442 if (e_config->raise_on_revert_focus)
443 evas_object_raise(ec->parent->frame);
444 }
445 else if (e_config->focus_revert_on_hide_or_close)
446 {
447 Eina_Bool unlock = ec->lock_focus_out;
448 ec->lock_focus_out = 1;
449 pec = e_desk_last_focused_focus(desk);
450 ec->lock_focus_out = unlock;
451 }
452 else if (e_config->focus_policy == E_FOCUS_MOUSE)
453 {
454 pec = e_client_under_pointer_get(desk, ec);
455 if (pec)
456 evas_object_focus_set(pec->frame, 1);
457 /* no autoraise/revert here because it's probably annoying */
458 }
459 }
460
461 static void
_e_client_free(E_Client * ec)462 _e_client_free(E_Client *ec)
463 {
464 if (ec->pixmap)
465 {
466 if (e_pixmap_free(ec->pixmap))
467 e_pixmap_client_set(ec->pixmap, NULL);
468 ec->pixmap = NULL;
469 }
470
471 if (ec->frame)
472 {
473 e_comp_object_redirected_set(ec->frame, 0);
474 e_comp_object_render_update_del(ec->frame);
475 }
476
477 E_OBJECT(ec)->references++;
478 if (ec->fullscreen)
479 {
480 ec->desk->fullscreen_clients = eina_list_remove(ec->desk->fullscreen_clients, ec);
481 if (!ec->desk->fullscreen_clients)
482 e_comp_render_queue();
483 }
484 if (ec->new_client)
485 e_comp->new_clients--;
486 if (ec->e.state.profile.use)
487 {
488 e_client_desk_window_profile_wait_desk_set(ec, NULL);
489
490 if (ec->e.state.profile.available_list)
491 {
492 int i;
493 for (i = 0; i < ec->e.state.profile.num; i++)
494 eina_stringshare_replace(&ec->e.state.profile.available_list[i], NULL);
495 E_FREE(ec->e.state.profile.available_list);
496 }
497
498 ec->e.state.profile.num = 0;
499
500 eina_stringshare_replace(&ec->e.state.profile.set, NULL);
501 eina_stringshare_replace(&ec->e.state.profile.wait, NULL);
502 eina_stringshare_replace(&ec->e.state.profile.name, NULL);
503 ec->e.state.profile.wait_for_done = 0;
504 ec->e.state.profile.use = 0;
505 }
506
507 if (ec->e.state.video_parent && ec->e.state.video_parent_client)
508 {
509 ec->e.state.video_parent_client->e.state.video_child =
510 eina_list_remove(ec->e.state.video_parent_client->e.state.video_child, ec);
511 }
512 if (ec->e.state.video_child)
513 {
514 E_Client *tmp;
515
516 EINA_LIST_FREE(ec->e.state.video_child, tmp)
517 tmp->e.state.video_parent_client = NULL;
518 }
519 E_FREE_FUNC(ec->internal_elm_win, evas_object_del);
520 E_FREE_FUNC(ec->desktop, efreet_desktop_free);
521 E_FREE_FUNC(ec->post_job, ecore_idle_enterer_del);
522
523 E_FREE_FUNC(ec->kill_timer, ecore_timer_del);
524 E_FREE_LIST(ec->pending_resize, free);
525
526 if (ec->remember)
527 {
528 E_Remember *rem;
529
530 rem = ec->remember;
531 ec->remember = NULL;
532 e_remember_unuse(rem);
533 }
534 ec->group = eina_list_free(ec->group);
535 ec->transients = eina_list_free(ec->transients);
536 ec->stick_desks = eina_list_free(ec->stick_desks);
537
538 E_FREE(ec->netwm.extra_types);
539 eina_stringshare_replace(&ec->border.name, NULL);
540 eina_stringshare_replace(&ec->bordername, NULL);
541 eina_stringshare_replace(&ec->icccm.name, NULL);
542 eina_stringshare_replace(&ec->icccm.class, NULL);
543 eina_stringshare_replace(&ec->icccm.title, NULL);
544 eina_stringshare_replace(&ec->icccm.icon_name, NULL);
545 eina_stringshare_replace(&ec->icccm.machine, NULL);
546 eina_stringshare_replace(&ec->icccm.window_role, NULL);
547 if ((ec->icccm.command.argc > 0) && (ec->icccm.command.argv))
548 {
549 int i;
550
551 for (i = 0; i < ec->icccm.command.argc; i++)
552 free(ec->icccm.command.argv[i]);
553 E_FREE(ec->icccm.command.argv);
554 }
555 eina_stringshare_replace(&ec->netwm.name, NULL);
556 eina_stringshare_replace(&ec->netwm.icon_name, NULL);
557 eina_stringshare_replace(&ec->internal_icon, NULL);
558 eina_stringshare_replace(&ec->internal_icon_key, NULL);
559 eina_stringshare_replace(&ec->uuid, NULL);
560
561 focus_stack = eina_list_remove(focus_stack, ec);
562 raise_stack = eina_list_remove(raise_stack, ec);
563
564 e_hints_client_list_set();
565 if (ec->e.state.profile.wait_desk)
566 {
567 e_object_delfn_del(E_OBJECT(ec->e.state.profile.wait_desk),
568 ec->e.state.profile.wait_desk_delfn);
569 ec->e.state.profile.wait_desk_delfn = NULL;
570 e_object_unref(E_OBJECT(ec->e.state.profile.wait_desk));
571 }
572 if (ec->stack.prev) ec->stack.prev->stack.next = ec->stack.next;
573 if (ec->stack.next) ec->stack.next->stack.prev = ec->stack.prev;
574
575 ec->e.state.profile.wait_desk = NULL;
576 evas_object_del(ec->frame);
577 E_OBJECT(ec)->references--;
578
579 free(ec);
580 }
581
582 static void
_e_client_del(E_Client * ec)583 _e_client_del(E_Client *ec)
584 {
585 E_Client *child;
586 E_Client_Volume_Sink *sink;
587
588 EINA_LIST_FREE(ec->sinks, sink)
589 e_client_volume_sink_remove(ec, sink);
590 for (child = ec->stack.next; child; child = child->stack.next)
591 e_client_act_close_begin(child);
592 ec->changed = 0;
593 focus_stack = eina_list_remove(focus_stack, ec);
594 raise_stack = eina_list_remove(raise_stack, ec);
595 if (ec->exe_inst)
596 {
597 if (ec->exe_inst->phony && (eina_list_count(ec->exe_inst->clients) == 1))
598 {
599 if (e_exec_phony_del(ec->exe_inst))
600 ec->exe_inst = NULL;
601 }
602 else
603 {
604 if (!ec->exe_inst->deleted)
605 {
606 ec->exe_inst->clients = eina_list_remove(ec->exe_inst->clients, ec);
607 ec->exe_inst = NULL;
608 }
609 }
610 }
611
612 _e_client_mouse_action_end(ec);
613 if (action_client == ec) _e_client_action_finish();
614 e_pointer_type_pop(e_comp->pointer, ec, NULL);
615
616 if (warp_client == ec)
617 {
618 E_FREE_FUNC(warp_timer, ecore_timer_del);
619 warp_client = NULL;
620 }
621
622 if ((client_drag) && (client_drag->data == ec))
623 {
624 e_object_del(E_OBJECT(client_drag));
625 client_drag = NULL;
626 }
627 if (ec->border_menu) e_menu_deactivate(ec->border_menu);
628 if (!stopping)
629 {
630 e_client_comp_hidden_set(ec, 1);
631 if (ec->frame) evas_object_pass_events_set(ec->frame, 1);
632 }
633
634 E_FREE_FUNC(ec->border_locks_dialog, e_object_del);
635 E_FREE_FUNC(ec->border_remember_dialog, e_object_del);
636 E_FREE_FUNC(ec->border_border_dialog, e_object_del);
637 E_FREE_FUNC(ec->border_prop_dialog, e_object_del);
638 E_FREE_FUNC(ec->color_editor, evas_object_del);
639 e_int_client_menu_del(ec);
640 E_FREE_FUNC(ec->raise_timer, ecore_timer_del);
641
642 if (ec->internal_elm_win)
643 evas_object_hide(ec->internal_elm_win);
644
645 if (ec->focused)
646 _e_client_revert_focus(ec);
647 if (ec->frame) evas_object_focus_set(ec->frame, 0);
648
649 E_FREE_FUNC(ec->ping_poller, ecore_poller_del);
650 eina_hash_del_by_key(clients_hash[e_pixmap_type_get(ec->pixmap)], &ec->pixmap);
651 /* must be called before parent/child clear */
652 _e_client_hook_call(E_CLIENT_HOOK_DEL, ec);
653 E_FREE(ec->comp_data);
654
655 if ((!ec->new_client) && (!stopping))
656 _e_client_event_simple(ec, E_EVENT_CLIENT_REMOVE);
657
658 if (ec->parent)
659 {
660 ec->parent->transients = eina_list_remove(ec->parent->transients, ec);
661 ec->parent = NULL;
662 }
663 EINA_LIST_FREE(ec->transients, child)
664 child->parent = NULL;
665
666 if (ec->leader)
667 {
668 ec->leader->group = eina_list_remove(ec->leader->group, ec);
669 if (ec->leader->modal == ec)
670 ec->leader->modal = NULL;
671 ec->leader = NULL;
672 }
673 EINA_LIST_FREE(ec->group, child)
674 child->leader = NULL;
675
676 e_comp->clients = eina_list_remove(e_comp->clients, ec);
677 if (ec->frame) e_comp_object_render_update_del(ec->frame);
678 }
679
680 ///////////////////////////////////////////
681
682 static Eina_Bool
_e_client_cb_kill_timer(void * data)683 _e_client_cb_kill_timer(void *data)
684 {
685 E_Client *ec = data;
686
687 // dont wait until it's hung -
688 // if (ec->hung)
689 // {
690 if (ec->netwm.pid > 1)
691 kill(ec->netwm.pid, SIGKILL);
692 // }
693 ec->kill_timer = NULL;
694 return ECORE_CALLBACK_CANCEL;
695 }
696
697 static Eina_Bool
_e_client_cb_ping_poller(void * data)698 _e_client_cb_ping_poller(void *data)
699 {
700 E_Client *ec;
701
702 ec = data;
703 if (ec->ping_ok)
704 {
705 if (ec->hung)
706 {
707 ec->hung = 0;
708 evas_object_smart_callback_call(ec->frame, "unhung", NULL);
709 E_FREE_FUNC(ec->kill_timer, ecore_timer_del);
710 }
711 }
712 else
713 {
714 /* if time between last ping and now is greater
715 * than half the ping interval... */
716 if ((ecore_loop_time_get() - ec->ping) >
717 ((e_config->ping_clients_interval *
718 ecore_poller_poll_interval_get(ECORE_POLLER_CORE)) / 2.0))
719 {
720 if (!ec->hung)
721 {
722 ec->hung = 1;
723 evas_object_smart_callback_call(ec->frame, "hung", NULL);
724 /* FIXME: if below dialog is up - hide it now */
725 }
726 if (ec->delete_requested)
727 {
728 /* FIXME: pop up dialog saying app is hung - kill client, or pid */
729 e_client_act_kill_begin(ec);
730 }
731 }
732 }
733 ec->ping_poller = NULL;
734 e_client_ping(ec);
735 return ECORE_CALLBACK_CANCEL;
736 }
737
738 ///////////////////////////////////////////
739
740 static int
_e_client_action_input_win_new(void)741 _e_client_action_input_win_new(void)
742 {
743 if (comp_grabbed)
744 {
745 CRI("DOUBLE COMP GRAB! ACK!!!!");
746 return 1;
747 }
748 comp_grabbed = e_comp_grab_input(1, 1);
749 if (!comp_grabbed) _e_client_action_input_win_del();
750 return comp_grabbed;
751 }
752
753 static void
_e_client_action_event_grabber_mouse_up(void * data EINA_UNUSED,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)754 _e_client_action_event_grabber_mouse_up(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
755 {
756 Evas_Event_Mouse_Down *ev = event_info;
757 E_Binding_Event_Mouse_Button ev2;
758
759 if (!action_client) return;
760 e_bindings_evas_event_mouse_button_convert(ev, &ev2);
761 e_client_mouse_up(action_client, ev->button, &ev->output, &ev2);
762 if (!action_client) return;
763 if (action_client->moving)
764 e_client_act_move_end(action_client, NULL);
765 if (!action_client) return;
766 if (e_client_util_resizing_get(action_client))
767 e_client_act_resize_end(action_client, NULL);
768 }
769
770 static void
_e_client_action_event_grabber_mouse_move(void * data EINA_UNUSED,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info)771 _e_client_action_event_grabber_mouse_move(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
772 {
773 Evas_Event_Mouse_Move *ev = event_info;
774 if (action_client)
775 e_client_mouse_move(action_client, &ev->cur.output);
776 }
777
778 static void
_e_client_action_event_grabber_init(E_Client * ec)779 _e_client_action_event_grabber_init(E_Client *ec)
780 {
781 action_rect = e_comp_canvas_event_grabber_add();
782 evas_object_event_callback_add(action_rect, EVAS_CALLBACK_MOUSE_UP, _e_client_action_event_grabber_mouse_up, NULL);
783 evas_object_event_callback_add(action_rect, EVAS_CALLBACK_MOUSE_MOVE, _e_client_action_event_grabber_mouse_move, NULL);
784 evas_object_smart_member_add(ec->frame, action_rect);
785 evas_object_resize(action_rect, e_comp->w, e_comp->h);
786 evas_object_layer_set(action_rect, EVAS_LAYER_MAX - 100);
787 evas_object_show(action_rect);
788 evas_object_event_grabber_freeze_when_visible_set(action_rect, 1);
789 e_comp_shape_queue();
790 }
791
792 static void
_e_client_action_init(E_Client * ec)793 _e_client_action_init(E_Client *ec)
794 {
795 action_orig.x = ec->x;
796 action_orig.y = ec->y;
797 action_orig.w = ec->w;
798 action_orig.h = ec->h;
799
800 if (action_client)
801 {
802 action_client->keyboard_resizing = 0;
803 if (action_client->internal_elm_win)
804 ecore_event_window_ignore_events(elm_win_window_id_get(action_client->internal_elm_win), 0);
805 }
806 action_client = ec;
807 if (ec->internal_elm_win)
808 ecore_event_window_ignore_events(elm_win_window_id_get(ec->internal_elm_win), 1);
809 }
810
811 static void
_e_client_action_restore_orig(E_Client * ec)812 _e_client_action_restore_orig(E_Client *ec)
813 {
814 if (action_client != ec)
815 return;
816
817 evas_object_geometry_set(ec->frame, action_orig.x, action_orig.y, action_orig.w, action_orig.h);
818 }
819
820 static int
_e_client_key_down_modifier_apply(int modifier,int value)821 _e_client_key_down_modifier_apply(int modifier, int value)
822 {
823 if (modifier & ECORE_EVENT_MODIFIER_CTRL) return value * 5;
824 else if (modifier & ECORE_EVENT_MODIFIER_ALT)
825 {
826 value /= 5;
827 if (value) return value;
828 else return 1;
829 }
830
831 return value;
832 }
833
834
835 static int
_e_client_move_begin(E_Client * ec)836 _e_client_move_begin(E_Client *ec)
837 {
838 if ((ec->fullscreen) || (ec->lock_user_location))
839 return 0;
840
841 /*
842 if (client_grabbed && !e_grabinput_get(e_client_util_pwin_get(ec), 0, e_client_util_pwin_get(ec)))
843 {
844 client_grabbed = 0;
845 return 0;
846 }
847 */
848 if (!_e_client_action_input_win_new()) return 0;
849 ec->moving = 1;
850 ecmove = ec;
851 if (!ec->lock_user_stacking)
852 {
853 if (e_config->border_raise_on_mouse_action)
854 evas_object_raise(ec->frame);
855 }
856
857 _e_client_hook_call(E_CLIENT_HOOK_MOVE_BEGIN, ec);
858 if (!ec->moving)
859 {
860 if (ecmove == ec) ecmove = NULL;
861 _e_client_action_input_win_del();
862 return 0;
863 }
864 E_FREE_FUNC(ec->raise_timer, ecore_timer_del);
865 _e_client_action_event_grabber_init(ec);
866 return 1;
867 }
868
869 static int
_e_client_move_end(E_Client * ec)870 _e_client_move_end(E_Client *ec)
871 {
872 //if (client_grabbed)
873 //{
874 //e_grabinput_release(e_client_util_pwin_get(ec), e_client_util_pwin_get(ec));
875 //client_grabbed = 0;
876 //}
877 _e_client_action_input_win_del();
878 e_pointer_mode_pop(ec, E_POINTER_MOVE);
879 ec->moving = 0;
880 _e_client_hook_call(E_CLIENT_HOOK_MOVE_END, ec);
881
882 ecmove = NULL;
883 return 1;
884 }
885
886 static Eina_Bool
_e_client_action_move_timeout(void * data EINA_UNUSED)887 _e_client_action_move_timeout(void *data EINA_UNUSED)
888 {
889 _e_client_move_end(action_client);
890 _e_client_action_finish();
891 return ECORE_CALLBACK_CANCEL;
892 }
893
894 static void
_e_client_action_move_timeout_add(void)895 _e_client_action_move_timeout_add(void)
896 {
897 double timeout = e_config->border_keyboard.timeout;
898 E_FREE_FUNC(action_timer, ecore_timer_del);
899 if (!EINA_DBL_NONZERO(timeout)) timeout = 5.0;
900 action_timer = ecore_timer_loop_add(timeout, _e_client_action_move_timeout, NULL);
901 }
902
903 static Eina_Bool
_e_client_move_key_down(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)904 _e_client_move_key_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
905 {
906 Ecore_Event_Key *ev = event;
907 int x, y, dx, dy;
908
909 if (!comp_grabbed) return ECORE_CALLBACK_RENEW;
910 if (!action_client)
911 {
912 ERR("no action_client!");
913 goto stop;
914 }
915
916 x = action_client->x;
917 y = action_client->y;
918
919 dx = e_config->border_keyboard.move.dx;
920 dx = _e_client_key_down_modifier_apply(ev->modifiers, dx);
921 dy = e_config->border_keyboard.move.dy;
922 dy = _e_client_key_down_modifier_apply(ev->modifiers, dy);
923
924 switch (e_util_key_geometry_action_get(ev->key, &x, &y, dx, dy))
925 {
926 case E_UTIL_ACTION_DONE:
927 goto stop;
928 break;
929 case E_UTIL_ACTION_ABORT:
930 _e_client_action_restore_orig(action_client);
931 goto stop;
932 break;
933 case E_UTIL_ACTION_DO:
934 evas_object_move(action_client->frame, x, y);
935 _e_client_action_move_timeout_add();
936 break;
937 case E_UTIL_ACTION_NONE:
938 default:
939 break;
940 }
941
942 return ECORE_CALLBACK_PASS_ON;
943
944 stop:
945 _e_client_move_end(action_client);
946 _e_client_action_finish();
947 return ECORE_CALLBACK_DONE;
948 }
949
950 static Eina_Bool
_e_client_move_mouse_down(void * data EINA_UNUSED,int type EINA_UNUSED,void * event EINA_UNUSED)951 _e_client_move_mouse_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
952 {
953 if (!comp_grabbed) return ECORE_CALLBACK_RENEW;
954
955 if (!action_client)
956 ERR("no action_client!");
957
958 _e_client_move_end(action_client);
959 _e_client_action_finish();
960 return ECORE_CALLBACK_DONE;
961 }
962
963 static void
_e_client_moveinfo_gather(E_Client * ec,const char * source)964 _e_client_moveinfo_gather(E_Client *ec, const char *source)
965 {
966 if (e_util_glob_match(source, "mouse,*,1"))
967 ec->moveinfo.down.button = 1;
968 else if (e_util_glob_match(source, "mouse,*,2"))
969 ec->moveinfo.down.button = 2;
970 else if (e_util_glob_match(source, "mouse,*,3"))
971 ec->moveinfo.down.button = 3;
972 else
973 ec->moveinfo.down.button = 0;
974 if ((ec->moveinfo.down.button >= 1) && (ec->moveinfo.down.button <= 3))
975 {
976 ec->moveinfo.down.mx = ec->mouse.last_down[ec->moveinfo.down.button - 1].mx;
977 ec->moveinfo.down.my = ec->mouse.last_down[ec->moveinfo.down.button - 1].my;
978 }
979 else
980 {
981 ec->moveinfo.down.mx = ec->mouse.current.mx;
982 ec->moveinfo.down.my = ec->mouse.current.my;
983 }
984 }
985
986 static void
_e_client_resize_handle(E_Client * ec)987 _e_client_resize_handle(E_Client *ec)
988 {
989 int x, y, w, h;
990 int new_x, new_y, new_w, new_h;
991 int tw, th;
992 Eina_List *skiplist = NULL;
993
994 if (e_comp->updating) return;
995 x = ec->x;
996 y = ec->y;
997 w = ec->w;
998 h = ec->h;
999
1000 if ((ec->resize_mode == E_POINTER_RESIZE_TR) ||
1001 (ec->resize_mode == E_POINTER_RESIZE_R) ||
1002 (ec->resize_mode == E_POINTER_RESIZE_BR))
1003 {
1004 if ((ec->moveinfo.down.button >= 1) &&
1005 (ec->moveinfo.down.button <= 3))
1006 w = ec->mouse.last_down[ec->moveinfo.down.button - 1].w +
1007 (ec->mouse.current.mx - ec->moveinfo.down.mx);
1008 else
1009 w = ec->moveinfo.down.w + (ec->mouse.current.mx - ec->moveinfo.down.mx);
1010 }
1011 else if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
1012 (ec->resize_mode == E_POINTER_RESIZE_L) ||
1013 (ec->resize_mode == E_POINTER_RESIZE_BL))
1014 {
1015 if ((ec->moveinfo.down.button >= 1) &&
1016 (ec->moveinfo.down.button <= 3))
1017 w = ec->mouse.last_down[ec->moveinfo.down.button - 1].w -
1018 (ec->mouse.current.mx - ec->moveinfo.down.mx);
1019 else
1020 w = ec->moveinfo.down.w - (ec->mouse.current.mx - ec->moveinfo.down.mx);
1021 }
1022
1023 if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
1024 (ec->resize_mode == E_POINTER_RESIZE_T) ||
1025 (ec->resize_mode == E_POINTER_RESIZE_TR))
1026 {
1027 if ((ec->moveinfo.down.button >= 1) &&
1028 (ec->moveinfo.down.button <= 3))
1029 h = ec->mouse.last_down[ec->moveinfo.down.button - 1].h -
1030 (ec->mouse.current.my - ec->moveinfo.down.my);
1031 else
1032 h = ec->moveinfo.down.h - (ec->mouse.current.my - ec->moveinfo.down.my);
1033 }
1034 else if ((ec->resize_mode == E_POINTER_RESIZE_BL) ||
1035 (ec->resize_mode == E_POINTER_RESIZE_B) ||
1036 (ec->resize_mode == E_POINTER_RESIZE_BR))
1037 {
1038 if ((ec->moveinfo.down.button >= 1) &&
1039 (ec->moveinfo.down.button <= 3))
1040 h = ec->mouse.last_down[ec->moveinfo.down.button - 1].h +
1041 (ec->mouse.current.my - ec->moveinfo.down.my);
1042 else
1043 h = ec->moveinfo.down.h + (ec->mouse.current.my - ec->moveinfo.down.my);
1044 }
1045
1046 tw = ec->w;
1047 th = ec->h;
1048
1049 if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
1050 (ec->resize_mode == E_POINTER_RESIZE_L) ||
1051 (ec->resize_mode == E_POINTER_RESIZE_BL))
1052 x += (tw - w);
1053 if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
1054 (ec->resize_mode == E_POINTER_RESIZE_T) ||
1055 (ec->resize_mode == E_POINTER_RESIZE_TR))
1056 y += (th - h);
1057
1058 skiplist = eina_list_append(skiplist, ec);
1059 e_resist_client_position(skiplist,
1060 ec->x, ec->y, ec->w, ec->h,
1061 x, y, w, h,
1062 &new_x, &new_y, &new_w, &new_h);
1063 eina_list_free(skiplist);
1064
1065 w = new_w;
1066 h = new_h;
1067 if (e_config->screen_limits == E_CLIENT_OFFSCREEN_LIMIT_ALLOW_NONE)
1068 {
1069 if (ec->zone)
1070 {
1071 w = MIN(w, ec->zone->w);
1072 h = MIN(h, ec->zone->h);
1073 }
1074 }
1075 e_client_resize_limit(ec, &new_w, &new_h);
1076 if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
1077 (ec->resize_mode == E_POINTER_RESIZE_L) ||
1078 (ec->resize_mode == E_POINTER_RESIZE_BL))
1079 new_x += (w - new_w);
1080 if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
1081 (ec->resize_mode == E_POINTER_RESIZE_T) ||
1082 (ec->resize_mode == E_POINTER_RESIZE_TR))
1083 new_y += (h - new_h);
1084
1085 evas_object_geometry_set(ec->frame, new_x, new_y, new_w, new_h);
1086 }
1087
1088 static int
_e_client_resize_end(E_Client * ec)1089 _e_client_resize_end(E_Client *ec)
1090 {
1091 _e_client_action_input_win_del();
1092 e_pointer_mode_pop(ec, ec->resize_mode);
1093 ec->resize_mode = E_POINTER_RESIZE_NONE;
1094
1095 /* If this border was maximized, we need to unset Maximized state or
1096 * on restart, E still thinks it's maximized */
1097 if (ec->maximized != E_MAXIMIZE_NONE)
1098 e_hints_window_maximized_set(ec, ec->maximized & E_MAXIMIZE_HORIZONTAL,
1099 ec->maximized & E_MAXIMIZE_VERTICAL);
1100
1101 _e_client_hook_call(E_CLIENT_HOOK_RESIZE_END, ec);
1102
1103 ecresize = NULL;
1104
1105 return 1;
1106 }
1107
1108
1109 static Eina_Bool
_e_client_action_resize_timeout(void * data EINA_UNUSED)1110 _e_client_action_resize_timeout(void *data EINA_UNUSED)
1111 {
1112 _e_client_resize_end(action_client);
1113 _e_client_action_finish();
1114 return ECORE_CALLBACK_CANCEL;
1115 }
1116
1117 static void
_e_client_action_resize_timeout_add(void)1118 _e_client_action_resize_timeout_add(void)
1119 {
1120 double timeout = e_config->border_keyboard.timeout;
1121 E_FREE_FUNC(action_timer, ecore_timer_del);
1122 if (!EINA_DBL_NONZERO(timeout)) timeout = 5.0;
1123 action_timer = ecore_timer_loop_add(timeout, _e_client_action_resize_timeout, NULL);
1124 }
1125
1126 static Eina_Bool
_e_client_resize_key_down(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)1127 _e_client_resize_key_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
1128 {
1129 Ecore_Event_Key *ev = event;
1130 int w, h, dx, dy;
1131
1132 if (!comp_grabbed) return ECORE_CALLBACK_RENEW;
1133 if (!action_client)
1134 {
1135 ERR("no action_client!");
1136 goto stop;
1137 }
1138
1139 w = action_client->w;
1140 h = action_client->h;
1141
1142 dx = e_config->border_keyboard.resize.dx;
1143 if (dx < action_client->icccm.step_w) dx = action_client->icccm.step_w;
1144 dx = _e_client_key_down_modifier_apply(ev->modifiers, dx);
1145 if (dx < action_client->icccm.step_w) dx = action_client->icccm.step_w;
1146
1147 dy = e_config->border_keyboard.resize.dy;
1148 if (dy < action_client->icccm.step_h) dy = action_client->icccm.step_h;
1149 dy = _e_client_key_down_modifier_apply(ev->modifiers, dy);
1150 if (dy < action_client->icccm.step_h) dy = action_client->icccm.step_h;
1151
1152 switch (e_util_key_geometry_action_get(ev->key, &w, &h, dx, dy))
1153 {
1154 case E_UTIL_ACTION_DONE:
1155 goto stop;
1156 break;
1157 case E_UTIL_ACTION_ABORT:
1158 _e_client_action_restore_orig(action_client);
1159 goto stop;
1160 break;
1161 case E_UTIL_ACTION_DO:
1162 if (e_config->screen_limits == E_CLIENT_OFFSCREEN_LIMIT_ALLOW_NONE)
1163 {
1164 if (action_client->zone)
1165 {
1166 w = MIN(w, action_client->zone->w);
1167 h = MIN(h, action_client->zone->h);
1168 }
1169 }
1170 e_client_resize_limit(action_client, &w, &h);
1171 evas_object_resize(action_client->frame, w, h);
1172 _e_client_action_resize_timeout_add();
1173 break;
1174 case E_UTIL_ACTION_NONE:
1175 default:
1176 break;
1177 }
1178
1179 return ECORE_CALLBACK_PASS_ON;
1180
1181 stop:
1182 _e_client_resize_end(action_client);
1183 _e_client_action_finish();
1184 return ECORE_CALLBACK_DONE;
1185 }
1186
1187 static Eina_Bool
_e_client_resize_mouse_down(void * data EINA_UNUSED,int type EINA_UNUSED,void * event EINA_UNUSED)1188 _e_client_resize_mouse_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
1189 {
1190 if (!comp_grabbed) return ECORE_CALLBACK_RENEW;
1191
1192 if (!action_client)
1193 ERR("no action_client!");
1194
1195 _e_client_resize_end(action_client);
1196 _e_client_action_finish();
1197 return ECORE_CALLBACK_DONE;
1198 }
1199
1200 ////////////////////////////////////////////////
1201
1202 static E_Client *
_e_client_under_pointer_helper(E_Desk * desk,E_Client * exclude,int x,int y)1203 _e_client_under_pointer_helper(E_Desk *desk, E_Client *exclude, int x, int y)
1204 {
1205 E_Client *ec = NULL, *cec;
1206
1207 E_CLIENT_REVERSE_FOREACH(cec)
1208 {
1209 /* If a border was specified which should be excluded from the list
1210 * (because it will be closed shortly for example), skip */
1211 if (e_client_util_ignored_get(cec) || (!e_client_util_desk_visible(cec, desk))) continue;
1212 if (!evas_object_visible_get(cec->frame)) continue;
1213 if ((exclude) && (cec == exclude)) continue;
1214 if (!E_INSIDE(x, y, cec->x, cec->y, cec->w, cec->h))
1215 continue;
1216 /* If the layer is higher, the position of the window is higher
1217 * (always on top vs always below) */
1218 if (!ec || (cec->layer > ec->layer))
1219 ec = cec;
1220 }
1221 return ec;
1222 }
1223
1224 ////////////////////////////////////////////////
1225
1226 static void
_e_client_zones_layout_calc(E_Client * ec,int * zx,int * zy,int * zw,int * zh)1227 _e_client_zones_layout_calc(E_Client *ec, int *zx, int *zy, int *zw, int *zh)
1228 {
1229 int x, y, w, h;
1230 E_Zone *zone_above, *zone_below, *zone_left, *zone_right;
1231
1232 if (!ec->zone) return;
1233 x = ec->zone->x;
1234 y = ec->zone->y;
1235 w = ec->zone->w;
1236 h = ec->zone->h;
1237
1238 if (eina_list_count(e_comp->zones) == 1)
1239 {
1240 if (zx) *zx = x;
1241 if (zy) *zy = y;
1242 if (zw) *zw = w;
1243 if (zh) *zh = h;
1244 return;
1245 }
1246
1247 zone_left = e_comp_zone_xy_get((x - w + 5), y);
1248 zone_right = e_comp_zone_xy_get((x + w + 5), y);
1249 zone_above = e_comp_zone_xy_get(x, (y - h + 5));
1250 zone_below = e_comp_zone_xy_get(x, (y + h + 5));
1251
1252 if (!(zone_above) && (y))
1253 zone_above = e_comp_zone_xy_get(x, (h - 5));
1254
1255 if (!(zone_left) && (x))
1256 zone_left = e_comp_zone_xy_get((x - 5), y);
1257
1258 if (zone_right)
1259 w = zone_right->x + zone_right->w;
1260
1261 if (zone_left)
1262 w = ec->zone->x + ec->zone->w;
1263
1264 if (zone_below)
1265 h = zone_below->y + zone_below->h;
1266
1267 if (zone_above)
1268 h = ec->zone->y + ec->zone->h;
1269
1270 if ((zone_left) && (zone_right))
1271 w = ec->zone->w + zone_right->x;
1272
1273 if ((zone_above) && (zone_below))
1274 h = ec->zone->h + zone_below->y;
1275
1276 if (x) x -= ec->zone->w;
1277 if (y) y -= ec->zone->h;
1278
1279 if (zx) *zx = x > 0 ? x : 0;
1280 if (zy) *zy = y > 0 ? y : 0;
1281 if (zw) *zw = w;
1282 if (zh) *zh = h;
1283 }
1284
1285 static void
_e_client_stay_within_canvas(E_Client * ec,int x,int y,int * new_x,int * new_y)1286 _e_client_stay_within_canvas(E_Client *ec, int x, int y, int *new_x, int *new_y)
1287 {
1288 int new_x_max, new_y_max;
1289 int zw, zh;
1290 Eina_Bool lw, lh;
1291
1292 if (!ec->zone)
1293 {
1294 if (new_x) *new_x = x;
1295 if (new_y) *new_y = y;
1296 return;
1297 }
1298
1299 _e_client_zones_layout_calc(ec, NULL, NULL, &zw, &zh);
1300
1301 new_x_max = zw - ec->w;
1302 new_y_max = zh - ec->h;
1303 lw = ec->w > zw ? EINA_TRUE : EINA_FALSE;
1304 lh = ec->h > zh ? EINA_TRUE : EINA_FALSE;
1305
1306 if (lw)
1307 {
1308 if (x <= new_x_max)
1309 *new_x = new_x_max;
1310 else if (x >= 0)
1311 *new_x = 0;
1312 }
1313 else
1314 {
1315 if (x >= new_x_max)
1316 *new_x = new_x_max;
1317 else if (x <= 0)
1318 *new_x = 0;
1319 }
1320
1321 if (lh)
1322 {
1323 if (y <= new_y_max)
1324 *new_y = new_y_max;
1325 else if (y >= 0)
1326 *new_y = 0;
1327 }
1328 else
1329 {
1330 if (y >= new_y_max)
1331 *new_y = new_y_max;
1332 else if (y <= 0)
1333 *new_y = 0;
1334 }
1335 }
1336
1337 static void
_e_client_reset_lost_window(E_Client * ec)1338 _e_client_reset_lost_window(E_Client *ec)
1339 {
1340 E_OBJECT_CHECK(ec);
1341
1342 if (ec->during_lost) return;
1343 ec->during_lost = EINA_TRUE;
1344
1345 if (ec->iconic) e_client_uniconify(ec);
1346 if (!ec->moving) e_comp_object_util_center(ec->frame);
1347
1348 evas_object_raise(ec->frame);
1349 if (!ec->lock_focus_out)
1350 evas_object_focus_set(ec->frame, 1);
1351
1352 e_client_pointer_warp_to_center(ec);
1353 ec->during_lost = EINA_FALSE;
1354 }
1355
1356 static void
_e_client_move_lost_window_to_center(E_Client * ec)1357 _e_client_move_lost_window_to_center(E_Client *ec)
1358 {
1359 int loss_overlap = 5;
1360 int zw, zh, zx, zy;
1361
1362 if (ec->during_lost) return;
1363 if (!ec->zone) return;
1364
1365 _e_client_zones_layout_calc(ec, &zx, &zy, &zw, &zh);
1366
1367 if (!E_INTERSECTS(zx + loss_overlap,
1368 zy + loss_overlap,
1369 zw - (2 * loss_overlap),
1370 zh - (2 * loss_overlap),
1371 ec->x, ec->y, ec->w, ec->h))
1372 {
1373 if (e_config->edge_flip_dragging)
1374 {
1375 Eina_Bool lf, rf, tf, bf;
1376
1377 lf = rf = tf = bf = EINA_TRUE;
1378
1379 if (ec->zone->desk_x_count <= 1) lf = rf = EINA_FALSE;
1380 else if (!e_config->desk_flip_wrap)
1381 {
1382 if (ec->zone->desk_x_current == 0) lf = EINA_FALSE;
1383 if (ec->zone->desk_x_current == (ec->zone->desk_x_count - 1)) rf = EINA_FALSE;
1384 }
1385
1386 if (ec->zone->desk_y_count <= 1) tf = bf = EINA_FALSE;
1387 else if (!e_config->desk_flip_wrap)
1388 {
1389 if (ec->zone->desk_y_current == 0) tf = EINA_FALSE;
1390 if (ec->zone->desk_y_current == (ec->zone->desk_y_count - 1)) bf = EINA_FALSE;
1391 }
1392
1393 if (!(lf) && (ec->x <= loss_overlap) && !(ec->zone->flip.switching))
1394 _e_client_reset_lost_window(ec);
1395
1396 if (!(rf) && (ec->x >= (ec->zone->w - loss_overlap)) && !(ec->zone->flip.switching))
1397 _e_client_reset_lost_window(ec);
1398
1399 if (!(tf) && (ec->y <= loss_overlap) && !(ec->zone->flip.switching))
1400 _e_client_reset_lost_window(ec);
1401
1402 if (!(bf) && (ec->y >= (ec->zone->h - loss_overlap)) && !(ec->zone->flip.switching))
1403 _e_client_reset_lost_window(ec);
1404 }
1405
1406 if (!e_config->edge_flip_dragging)
1407 _e_client_reset_lost_window(ec);
1408 }
1409 }
1410
1411 ////////////////////////////////////////////////
1412 static void
_e_client_zone_update(E_Client * ec)1413 _e_client_zone_update(E_Client *ec)
1414 {
1415 Eina_List *l;
1416 E_Zone *zone;
1417
1418 /* still within old zone - leave it there */
1419 if (ec->zone && E_INTERSECTS(ec->x, ec->y, ec->w, ec->h,
1420 ec->zone->x, ec->zone->y, ec->zone->w, ec->zone->h))
1421 return;
1422 /* find a new zone */
1423 EINA_LIST_FOREACH(e_comp->zones, l, zone)
1424 {
1425 if (E_INTERSECTS(ec->x, ec->y, ec->w, ec->h,
1426 zone->x, zone->y, zone->w, zone->h))
1427 {
1428 e_client_zone_set(ec, zone);
1429 return;
1430 }
1431 }
1432 }
1433
1434 ////////////////////////////////////////////////
1435
1436 E_API Eina_List *
e_client_stack_list_prepare(E_Client * ec)1437 e_client_stack_list_prepare(E_Client *ec)
1438 {
1439 E_Client *ec2;
1440 Eina_List *list = NULL;
1441
1442 for (ec2 = ec->stack.prev; ec2; ec2 = ec2->stack.prev)
1443 {
1444 ec2->stack.ignore++;
1445 list = eina_list_prepend(list, ec2);
1446 }
1447 ec->stack.ignore++;
1448 list = eina_list_append(list, ec);
1449 for (ec2 = ec->stack.next; ec2; ec2 = ec2->stack.next)
1450 {
1451 ec2->stack.ignore++;
1452 list = eina_list_append(list, ec2);
1453 }
1454 return list;
1455 }
1456
1457 E_API void
e_client_stack_list_finish(Eina_List * list)1458 e_client_stack_list_finish(Eina_List *list)
1459 {
1460 E_Client *ec;
1461
1462 EINA_LIST_FREE(list, ec) ec->stack.ignore--;
1463 }
1464
1465 E_API E_Client *
e_client_stack_top_get(E_Client * ec)1466 e_client_stack_top_get(E_Client *ec)
1467 {
1468 E_Client *ec2;
1469
1470 for (ec2 = ec; ec2; ec2 = ec2->stack.next)
1471 {
1472 if (!ec2->stack.next) return ec2;
1473 }
1474 return ec;
1475 }
1476
1477 E_API E_Client *
e_client_stack_bottom_get(E_Client * ec)1478 e_client_stack_bottom_get(E_Client *ec)
1479 {
1480 E_Client *ec2;
1481
1482 for (ec2 = ec; ec2; ec2 = ec2->stack.prev)
1483 {
1484 if (!ec2->stack.prev) return ec2;
1485 }
1486 return ec;
1487 }
1488
1489 E_API E_Client *
e_client_stack_active_adjust(E_Client * ec)1490 e_client_stack_active_adjust(E_Client *ec)
1491 {
1492 E_Client *pec = ec;
1493 if ((!ec->stack.prev) && (!ec->stack.next)) return ec;
1494 ec = e_client_stack_top_get(ec);
1495 for (; ec; ec = ec->stack.prev)
1496 {
1497 if (e_object_is_del(E_OBJECT(ec))) continue;
1498 if (ec->stack.focus_skip) continue;
1499 if (ec->iconic) continue;
1500 if (ec->visible) break;
1501 }
1502 if (!ec) ec = pec;
1503 return ec;
1504 }
1505
1506 E_API Eina_Bool
e_client_stack_focused_get(E_Client * ec)1507 e_client_stack_focused_get(E_Client *ec)
1508 {
1509 E_Client *ec2;
1510
1511 ec2 = e_client_stack_bottom_get(ec);
1512 for (; ec2; ec2 = ec2->stack.next)
1513 {
1514 if (ec2->focused) return EINA_TRUE;
1515 }
1516 return EINA_FALSE;
1517 }
1518
1519 E_API Eina_Bool
e_client_stack_iconified_get(E_Client * ec)1520 e_client_stack_iconified_get(E_Client *ec)
1521 {
1522 E_Client *ec2;
1523
1524 ec2 = e_client_stack_bottom_get(ec);
1525 for (; ec2; ec2 = ec2->stack.next)
1526 {
1527 if (ec2->iconic) return EINA_TRUE;
1528 }
1529 return EINA_FALSE;
1530 }
1531
1532 E_API Eina_Bool
e_client_stack_urgent_get(E_Client * ec)1533 e_client_stack_urgent_get(E_Client *ec)
1534 {
1535 E_Client *ec2;
1536
1537 ec2 = e_client_stack_bottom_get(ec);
1538 for (; ec2; ec2 = ec2->stack.next)
1539 {
1540 if (ec2->urgent) return EINA_TRUE;
1541 }
1542 return EINA_FALSE;
1543 }
1544
1545 ////////////////////////////////////////////////
1546
1547 static void
_e_client_cb_evas_hide(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)1548 _e_client_cb_evas_hide(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1549 {
1550 E_Client *ec = data;
1551
1552 if (stopping) return; //ignore all of this if we're shutting down!
1553 if (e_object_is_del(data)) return; //client is about to die
1554 _e_client_mouse_action_end(ec);
1555 if (action_client == ec) _e_client_action_finish();
1556 if (!evas_object_pass_events_get(ec->frame))
1557 e_pointer_type_pop(e_comp->pointer, ec, NULL);
1558
1559 if (!ec->hidden)
1560 {
1561 if (ec->focused)
1562 _e_client_revert_focus(ec);
1563 }
1564 ec->want_focus = ec->take_focus = 0;
1565
1566 ec->post_show = 0;
1567
1568 if (ec->new_client || ec->iconic) return;
1569 _e_client_event_simple(ec, E_EVENT_CLIENT_HIDE);
1570 }
1571
1572 static void
_e_client_cb_evas_shade_done(void * data,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)1573 _e_client_cb_evas_shade_done(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1574 {
1575 E_Client *ec = data;
1576
1577 ec->shading = 0;
1578 ec->shaded = !(ec->shaded);
1579 ec->changes.shaded = 1;
1580 ec->changes.shading = 1;
1581 e_client_comp_hidden_set(ec, ec->shaded);
1582 }
1583
1584 static void
_e_client_cb_evas_move(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)1585 _e_client_cb_evas_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1586 {
1587 E_Client *ec = data;
1588 Evas_Coord x, y;
1589
1590 ec->pre_res_change.valid = 0;
1591 if (ec->internal_elm_win)
1592 {
1593 EC_CHANGED(ec);
1594 ec->changes.pos = 1;
1595 }
1596
1597 _e_client_event_simple(ec, E_EVENT_CLIENT_MOVE);
1598
1599 if (!ec->ignored) _e_client_zone_update(ec);
1600 evas_object_geometry_get(ec->frame, &x, &y, NULL, NULL);
1601 if (ec->stack.prev || ec->stack.next)
1602 {
1603 // do nothing - handled by idle enterer eval
1604 }
1605 else
1606 {
1607 if ((e_config->transient.move) && (ec->transients))
1608 {
1609 Eina_List *list = eina_list_clone(ec->transients);
1610 E_Client *child;
1611
1612 EINA_LIST_FREE(list, child)
1613 {
1614 if (child->placed)
1615 evas_object_move(child->frame,
1616 child->x + x - ec->pre_cb.x,
1617 child->y + y - ec->pre_cb.y);
1618 }
1619 }
1620 }
1621 if (ec->moving || (ecmove == ec))
1622 _e_client_hook_call(E_CLIENT_HOOK_MOVE_UPDATE, ec);
1623 e_remember_update(ec);
1624 if (ec->fullscreen || (ec->maximized & E_MAXIMIZE_DIRECTION))
1625 e_hints_window_size_set(ec);
1626 ec->pre_cb.x = x; ec->pre_cb.y = y;
1627 }
1628
1629 static void
_e_client_cb_evas_resize(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)1630 _e_client_cb_evas_resize(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1631 {
1632 E_Client *ec = data;
1633 Evas_Coord x, y, w, h;
1634
1635 ec->pre_res_change.valid = 0;
1636
1637 _e_client_event_simple(ec, E_EVENT_CLIENT_RESIZE);
1638
1639 evas_object_geometry_get(ec->frame, &x, &y, &w, &h);
1640 if (ec->stack.prev || ec->stack.next)
1641 {
1642 // do nothing - handled by idle enterer eval
1643 }
1644 else
1645 {
1646 if ((e_config->transient.resize) && (ec->transients))
1647 {
1648 Eina_List *list = eina_list_clone(ec->transients);
1649 E_Client *child;
1650
1651 EINA_LIST_FREE(list, child)
1652 {
1653 Evas_Coord nx, ny, nw, nh;
1654
1655 if (!child->placed) continue;
1656
1657 if ((ec->pre_cb.w > 0) && (ec->pre_cb.h > 0))
1658 {
1659 nx = x + (((child->x - x) * w) / ec->pre_cb.w);
1660 ny = y + (((child->y - y) * h) / ec->pre_cb.h);
1661 nw = (child->w * w) / ec->pre_cb.w;
1662 nh = (child->h * h) / ec->pre_cb.h;
1663 nx += ((nw - child->w) / 2);
1664 ny += ((nh - child->h) / 2);
1665 evas_object_move(child->frame, nx, ny);
1666 }
1667 }
1668 }
1669 }
1670
1671 if (e_client_util_resizing_get(ec) || (ecresize == ec))
1672 _e_client_hook_call(E_CLIENT_HOOK_RESIZE_UPDATE, ec);
1673 e_remember_update(ec);
1674 if (ec->fullscreen || (ec->maximized & E_MAXIMIZE_DIRECTION))
1675 e_hints_window_size_set(ec);
1676 ec->pre_cb.w = w; ec->pre_cb.h = h;
1677 }
1678
1679 static void
_e_client_cb_evas_show(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)1680 _e_client_cb_evas_show(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1681 {
1682 _e_client_event_simple(data, E_EVENT_CLIENT_SHOW);
1683 }
1684
1685 static void
_e_client_cb_evas_restack(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)1686 _e_client_cb_evas_restack(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1687 {
1688 E_Client *ec = data;
1689
1690 if (ec->layer_block) return;
1691 if (ec->stack.prev || ec->stack.next)
1692 {
1693 if (ec->stack.ignore == 0)
1694 {
1695 Eina_List *l, *list = e_client_stack_list_prepare(ec);
1696 E_Client *child;
1697
1698 EINA_LIST_FOREACH(list, l, child)
1699 {
1700 if (child == ec) break;
1701 evas_object_stack_below(child->frame, ec->frame);
1702 }
1703 EINA_LIST_REVERSE_FOREACH(list, l, child)
1704 {
1705 if (child == ec) break;
1706 evas_object_stack_above(child->frame, ec->frame);
1707 }
1708 e_client_stack_list_finish(list);
1709 }
1710 }
1711 else
1712 {
1713 if (e_config->transient.raise && ec->transients)
1714 e_client_transients_restack(ec);
1715 }
1716 if (ec->unredirected_single) return;
1717 e_remember_update(ec);
1718 _e_client_event_simple(ec, E_EVENT_CLIENT_STACK);
1719 }
1720
1721 ////////////////////////////////////////////////
1722
1723 static void
_e_client_maximize_done(void * data,E_Efx_Map_Data * emd EINA_UNUSED,Evas_Object * obj)1724 _e_client_maximize_done(void *data, E_Efx_Map_Data *emd EINA_UNUSED, Evas_Object *obj)
1725 {
1726 E_Client *ec = data;
1727 ec->maximize_override = 0;
1728 ec->agent = NULL;
1729 evas_object_del(obj);
1730 }
1731
1732 static Eina_Bool
_e_client_maximize_run(E_Client * ec,int x,int y,int w,int h)1733 _e_client_maximize_run(E_Client *ec, int x, int y, int w, int h)
1734 {
1735 int pw, ph;
1736 Eina_Bool disabled = EINA_FALSE;
1737 if (e_pixmap_size_get(ec->pixmap, &pw, &ph))
1738 {
1739 e_comp_object_frame_wh_adjust(ec->frame, pw, ph, &pw, &ph);
1740 disabled = (w == pw) && (h == ph);
1741 }
1742 if ((!disabled) && e_config->window_maximize_animate && (!ec->maximize_anims_disabled) &&
1743 (!starting) && (!ec->changes.need_maximize))
1744 {
1745 evas_object_del(ec->agent);
1746 ec->agent = e_comp_object_agent_add(ec->frame);
1747 e_efx_resize(ec->agent, e_config->window_maximize_transition, E_EFX_POINT(x, y),
1748 w, h, e_config->window_maximize_time, _e_client_maximize_done, ec);
1749 return EINA_TRUE;
1750 }
1751 evas_object_geometry_set(ec->frame, x, y, w, h);
1752 return EINA_FALSE;
1753 }
1754
1755 ////////////////////////////////////////////////
1756
1757 static void
_e_client_eval(E_Client * ec)1758 _e_client_eval(E_Client *ec)
1759 {
1760 int rem_change = 0;
1761 int send_event = 1;
1762 unsigned int prop = 0;
1763 int zx = 0, zy = 0, zw = 0, zh = 0;
1764
1765
1766 if (e_object_is_del(E_OBJECT(ec)))
1767 {
1768 CRI("_e_client_eval(%p) with deleted border! - %d\n", ec, ec->new_client);
1769 ec->changed = 0;
1770 return;
1771 }
1772
1773 if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_PRE_NEW_CLIENT, ec)) return;
1774
1775 if ((ec->new_client) && (!e_client_util_ignored_get(ec)) && (ec->zone))
1776 {
1777 _e_client_event_simple(ec, E_EVENT_CLIENT_ADD);
1778 e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh);
1779 /* enforce wm size hints for initial sizing */
1780 if (e_config->screen_limits == E_CLIENT_OFFSCREEN_LIMIT_ALLOW_NONE)
1781 {
1782 ec->w = MIN(ec->w, ec->zone->w);
1783 ec->h = MIN(ec->h, ec->zone->h);
1784 }
1785 e_client_resize_limit(ec, &ec->w, &ec->h);
1786
1787 if (ec->re_manage && e_comp_object_frame_exists(ec->frame))
1788 {
1789 int x = ec->x, y = ec->y;
1790 if (ec->x) e_comp_object_frame_xy_adjust(ec->frame, ec->x, 0, &ec->x, NULL);
1791 if (ec->y) e_comp_object_frame_xy_adjust(ec->frame, 0, ec->y, NULL, &ec->y);
1792 if ((x != ec->x) || (y != ec->y)) ec->changes.pos = 1;
1793 ec->placed = 1;
1794 ec->pre_cb.x = ec->x; ec->pre_cb.y = ec->y;
1795 }
1796
1797 if ((ec->stack.prev) && (!ec->dialog))
1798 {
1799 E_Client *ec2 = e_client_stack_bottom_get(ec);
1800
1801 ec->stack.ignore++;
1802 evas_object_move(ec->frame, ec2->x, ec2->y);
1803 evas_object_resize(ec->frame, ec2->w, ec2->h);
1804 ec->stack.ignore--;
1805 }
1806 }
1807 if (ec->new_client && (!ec->override))
1808 e_hints_window_init(ec);
1809 if ((!e_client_util_ignored_get(ec)) && ec->zone && ec->visible && (!ec->placed))
1810 {
1811 e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh);
1812 if (ec->parent)
1813 {
1814 Eina_Bool centered = EINA_FALSE;
1815 if (ec->parent->zone != e_zone_current_get())
1816 {
1817 e_client_zone_set(ec, ec->parent->zone);
1818 e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh);
1819 }
1820
1821 if (evas_object_visible_get(ec->parent->frame))
1822 {
1823 if ((!E_CONTAINS(ec->x, ec->y, ec->w, ec->h, zx, zy, zw, zh)) ||
1824 (!E_CONTAINS(ec->x, ec->y, ec->w, ec->h, ec->parent->x, ec->parent->y, ec->parent->w, ec->parent->h)))
1825 {
1826 int x, y;
1827
1828 e_comp_object_util_center_pos_get(ec->parent->frame, &x, &y);
1829 if (E_CONTAINS(x, y, ec->w, ec->h, zx, zy, zw, zh))
1830 {
1831 ec->x = x, ec->y = y;
1832 }
1833 else
1834 {
1835 x = ec->parent->x;
1836 y = ec->parent->y;
1837 if (!E_CONTAINS(x, y, ec->w, ec->h, zx, zy, zw, zh))
1838 {
1839 e_comp_object_util_center_on(ec->frame,
1840 ec->parent->frame);
1841 centered = 1;
1842 }
1843 }
1844 ec->changes.pos = 1;
1845 }
1846 }
1847 else
1848 {
1849 e_comp_object_util_center_on(ec->frame,
1850 ec->parent->frame);
1851 centered = 1;
1852 }
1853 if (centered) //test for offscreen
1854 {
1855 if (!E_CONTAINS(ec->x, ec->y, ec->w, ec->h, zx, zy, zw, zh))
1856 {
1857 if (ec->x < zx)
1858 ec->x = ec->parent->x;
1859 if (ec->y < zy)
1860 ec->y = ec->parent->y;
1861 if (ec->x + ec->w > zx + zw)
1862 ec->x = ec->parent->x + ec->parent->w - ec->w;
1863 if (ec->y + ec->h > zy + zh)
1864 ec->y = ec->parent->y + ec->parent->h - ec->h;
1865 ec->changes.pos = 1;
1866 }
1867 }
1868 ec->placed = 1;
1869 ec->pre_cb.x = ec->x; ec->pre_cb.y = ec->y;
1870 }
1871 #if 0
1872 else if ((ec->leader) && (ec->dialog))
1873 {
1874 /* TODO: Place in center of group */
1875 }
1876 #endif
1877 else if (ec->dialog)
1878 {
1879 E_Client *trans_ec = NULL;
1880
1881 if (ec->icccm.transient_for)
1882 trans_ec = e_pixmap_find_client(E_PIXMAP_TYPE_X, ec->icccm.transient_for);
1883 if (trans_ec)
1884 {
1885 // if transient for a window and not placed, center on
1886 // transient parent if found
1887 ec->x = trans_ec->x + ((trans_ec->w - ec->w) / 2);
1888 ec->y = trans_ec->y + ((trans_ec->h - ec->h) / 2);
1889 }
1890 else
1891 {
1892 ec->x = zx + ((zw - ec->w) / 2);
1893 ec->y = zy + ((zh - ec->h) / 2);
1894 }
1895 ec->changes.pos = 1;
1896 ec->placed = 1;
1897 ec->pre_cb.x = ec->x; ec->pre_cb.y = ec->y;
1898 }
1899
1900 if (!ec->placed)
1901 {
1902 Eina_List *skiplist = NULL;
1903 int new_x, new_y, t = 0;
1904 E_Client *trans_ec = NULL;
1905
1906 if (zw > ec->w)
1907 new_x = zx + (rand() % (zw - ec->w));
1908 else
1909 new_x = zx;
1910 if (zh > ec->h)
1911 new_y = zy + (rand() % (zh - ec->h));
1912 else
1913 new_y = zy;
1914
1915 e_comp_object_frame_geometry_get(ec->frame, NULL, NULL, &t, NULL);
1916
1917 if (ec->icccm.transient_for)
1918 trans_ec = e_pixmap_find_client(E_PIXMAP_TYPE_X, ec->icccm.transient_for);
1919 if (trans_ec)
1920 {
1921 // if transient for a window and not placed, center on
1922 // transient parent if found
1923 new_x = trans_ec->x + ((trans_ec->w - ec->w) / 2);
1924 new_y = trans_ec->y + ((trans_ec->h - ec->h) / 2);
1925 }
1926 else if ((e_config->window_placement_policy == E_WINDOW_PLACEMENT_SMART) || (e_config->window_placement_policy == E_WINDOW_PLACEMENT_ANTIGADGET))
1927 {
1928 skiplist = eina_list_append(skiplist, ec);
1929 if (ec->transients)
1930 skiplist = eina_list_merge(skiplist, eina_list_clone(ec->transients));
1931 if (ec->desk)
1932 e_place_desk_region_smart(ec->desk, skiplist,
1933 ec->x, ec->y, ec->w, ec->h,
1934 &new_x, &new_y);
1935 else
1936 e_place_zone_region_smart(ec->zone, skiplist,
1937 ec->x, ec->y, ec->w, ec->h,
1938 &new_x, &new_y);
1939 eina_list_free(skiplist);
1940 }
1941 else if (e_config->window_placement_policy == E_WINDOW_PLACEMENT_MANUAL)
1942 {
1943 e_place_zone_manual(ec->zone, ec->w, t, &new_x, &new_y);
1944 }
1945 else
1946 {
1947 e_place_zone_cursor(ec->zone, ec->x, ec->y, ec->w, ec->h,
1948 t, &new_x, &new_y);
1949 }
1950 ec->x = new_x;
1951 ec->y = new_y;
1952 ec->changes.pos = 1;
1953 ec->pre_cb.x = ec->x; ec->pre_cb.y = ec->y;
1954 }
1955 else if (!E_INTERSECTS(ec->x, ec->y, ec->w, ec->h, zx, zy, zw, zh))
1956 {
1957 /* If an ec is placed out of bound, fix it! */
1958 ec->x = zx + ((zw - ec->w) / 2);
1959 ec->y = zy + ((zh - ec->h) / 2);
1960 ec->changes.pos = 1;
1961 }
1962
1963 /* Recreate state */
1964 if ((ec->e.state.centered) &&
1965 ((!ec->remember) ||
1966 ((ec->remember) && (!(ec->remember->apply & E_REMEMBER_APPLY_POS)))))
1967 {
1968 ec->x = zx + (zw - ec->w) / 2;
1969 ec->y = zy + (zh - ec->h) / 2;
1970 ec->changes.pos = 1;
1971 }
1972
1973 /* if the explicit geometry request asks for the app to be
1974 * in another zone - well move it there */
1975 {
1976 E_Zone *zone = NULL;
1977 int x, y;
1978
1979 x = MAX(ec->x, 0);
1980 y = MAX(ec->y, 0);
1981 if ((!ec->re_manage) && ((ec->x != x) || (ec->y != y)))
1982 zone = e_comp_zone_xy_get(x, y);
1983
1984 if (!zone)
1985 {
1986 zone = e_comp_zone_xy_get(ec->x + (ec->w / 2), ec->y + (ec->h / 2));
1987 if (zone)
1988 {
1989 E_Zone *z2 = e_comp_zone_xy_get(ec->x, ec->y);
1990
1991 if (z2 && (z2 != zone))
1992 {
1993 size_t psz = 0;
1994 E_Zone *zf = z2;
1995 Eina_List *l;
1996
1997 EINA_LIST_FOREACH(e_comp->zones, l, z2)
1998 {
1999 int w, h;
2000
2001 x = ec->x, y = ec->y, w = ec->w, h = ec->h;
2002 E_RECTS_CLIP_TO_RECT(x, y, w, h, z2->x, z2->y, z2->w, z2->h);
2003 if (w * h == z2->w * z2->h)
2004 {
2005 /* client fully covering zone */
2006 zf = z2;
2007 break;
2008 }
2009 if ((unsigned)(w * h) > psz)
2010 {
2011 psz = w * h;
2012 zf = z2;
2013 }
2014 }
2015 zone = zf;
2016 }
2017 }
2018 }
2019 if (!zone)
2020 zone = e_comp_zone_xy_get(ec->x, ec->y);
2021 if (!zone)
2022 zone = e_comp_zone_xy_get(ec->x + ec->w - 1, ec->y);
2023 if (!zone)
2024 zone = e_comp_zone_xy_get(ec->x + ec->w - 1, ec->y + ec->h - 1);
2025 if (!zone)
2026 zone = e_comp_zone_xy_get(ec->x, ec->y + ec->h - 1);
2027 if ((zone) && (zone != ec->zone))
2028 e_client_zone_set(ec, zone);
2029 }
2030 }
2031
2032 if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_POST_NEW_CLIENT, ec)) return;
2033
2034 /* effect changes to the window border itself */
2035 if ((ec->changes.shading))
2036 {
2037 /* show at start of unshade (but don't hide until end of shade) */
2038 //if (ec->shaded)
2039 //ecore_x_window_raise(ec->win);
2040 ec->changes.shading = 0;
2041 send_event = 0;
2042 rem_change = 1;
2043 }
2044 if (ec->changes.shaded) send_event = 0;
2045 if ((ec->changes.shaded) && (ec->changes.pos) && (ec->changes.size))
2046 {
2047 //if (ec->shaded)
2048 //ecore_x_window_lower(ec->win);
2049 //else
2050 //ecore_x_window_raise(ec->win);
2051 ec->changes.shaded = 0;
2052 rem_change = 1;
2053 }
2054 else if ((ec->changes.shaded) && (ec->changes.pos))
2055 {
2056 //if (ec->shaded)
2057 //ecore_x_window_lower(ec->win);
2058 //else
2059 //ecore_x_window_raise(ec->win);
2060 ec->changes.size = 1;
2061 ec->changes.shaded = 0;
2062 rem_change = 1;
2063 }
2064 else if ((ec->changes.shaded) && (ec->changes.size))
2065 {
2066 //if (ec->shaded)
2067 //ecore_x_window_lower(ec->win);
2068 //else
2069 //ecore_x_window_raise(ec->win);
2070 ec->changes.shaded = 0;
2071 rem_change = 1;
2072 }
2073 else if (ec->changes.shaded)
2074 {
2075 //if (ec->shaded)
2076 //ecore_x_window_lower(ec->win);
2077 //else
2078 //ecore_x_window_raise(ec->win);
2079 ec->changes.shaded = 0;
2080 rem_change = 1;
2081 }
2082
2083 if (ec->changes.size)
2084 {
2085 ec->changes.size = 0;
2086 if ((!ec->shaded) && (!ec->shading))
2087 evas_object_resize(ec->frame, ec->w, ec->h);
2088
2089 rem_change = 1;
2090 prop |= E_CLIENT_PROPERTY_SIZE;
2091 }
2092 if (ec->changes.pos)
2093 {
2094 Eina_Bool placed = ec->placed;
2095
2096 ec->changes.pos = 0;
2097 evas_object_move(ec->frame, ec->x, ec->y);
2098 if (e_config->window_placement_policy == E_WINDOW_PLACEMENT_MANUAL)
2099 ec->placed = placed;
2100 rem_change = 1;
2101 prop |= E_CLIENT_PROPERTY_POS;
2102 }
2103 if (ec->changes.need_rescale)
2104 {
2105 e_client_rescale(ec);
2106 ec->changes.need_rescale = 0;
2107 }
2108
2109 if (ec->changes.reset_gravity)
2110 {
2111 ec->changes.reset_gravity = 0;
2112 rem_change = 1;
2113 prop |= E_CLIENT_PROPERTY_GRAVITY;
2114 }
2115
2116 if ((ec->changes.visible) && (ec->visible) && (ec->new_client) && (!ec->iconic))
2117 {
2118 int x, y;
2119
2120 ecore_evas_pointer_xy_get(e_comp->ee, &x, &y);
2121 if ((!ec->placed) && (!ec->re_manage) &&
2122 (e_config->window_placement_policy == E_WINDOW_PLACEMENT_MANUAL) &&
2123 (!((ec->icccm.transient_for != 0) ||
2124 (ec->dialog))) &&
2125 (!ecmove) && (!ecresize))
2126 {
2127 /* Set this window into moving state */
2128
2129 ec->cur_mouse_action = e_action_find("window_move");
2130 if (ec->next_mouse_action_ignore)
2131 ec->cur_mouse_action = NULL;
2132 if (ec->cur_mouse_action)
2133 {
2134 if ((!ec->cur_mouse_action->func.end_mouse) &&
2135 (!ec->cur_mouse_action->func.end))
2136 ec->cur_mouse_action = NULL;
2137 if (ec->cur_mouse_action)
2138 {
2139 int t;
2140 ec->x = x - (ec->w >> 1);
2141 e_comp_object_frame_geometry_get(ec->frame, NULL, NULL, &t, NULL);
2142 ec->y = y - (t >> 1);
2143 EC_CHANGED(ec);
2144 ec->changes.pos = 1;
2145 }
2146 }
2147 }
2148
2149 evas_object_show(ec->frame);
2150 if (ec->cur_mouse_action)
2151 {
2152 ec->moveinfo.down.x = ec->x;
2153 ec->moveinfo.down.y = ec->y;
2154 ec->moveinfo.down.w = ec->w;
2155 ec->moveinfo.down.h = ec->h;
2156 ec->mouse.current.mx = x;
2157 ec->mouse.current.my = y;
2158 ec->moveinfo.down.button = 0;
2159 ec->moveinfo.down.mx = x;
2160 ec->moveinfo.down.my = y;
2161
2162 e_object_ref(E_OBJECT(ec->cur_mouse_action));
2163 ec->cur_mouse_action->func.go(E_OBJECT(ec), NULL);
2164 if (e_config->border_raise_on_mouse_action)
2165 evas_object_raise(ec->frame);
2166 evas_object_focus_set(ec->frame, 1);
2167 }
2168 if (evas_object_visible_get(ec->frame))
2169 ec->changes.visible = 0;
2170 }
2171 else if ((ec->changes.visible) && (ec->new_client))
2172 {
2173 ec->changes.visible = 0;
2174 if (!ec->iconic)
2175 _e_client_event_simple(ec, E_EVENT_CLIENT_HIDE);
2176 }
2177
2178 if (ec->changes.icon)
2179 {
2180 if (!ec->new_client)
2181 E_FREE_FUNC(ec->desktop, efreet_desktop_free);
2182 if (ec->remember && ec->remember->prop.desktop_file)
2183 {
2184 Efreet_Desktop *d;
2185 const char *desktop = ec->remember->prop.desktop_file;
2186
2187 d = efreet_desktop_get(desktop);
2188 if (!d)
2189 d = efreet_util_desktop_name_find(desktop);
2190 if (d)
2191 {
2192 efreet_desktop_free(ec->desktop);
2193 ec->desktop = d;
2194 }
2195 }
2196 if (!ec->desktop)
2197 {
2198 if (ec->steam.steam_game_id)
2199 {
2200 Efreet_Desktop *d;
2201 Eina_List *desks = efreet_util_desktop_name_glob_list("*");
2202 EINA_LIST_FREE(desks, d)
2203 {
2204 if (!d->exec) continue;
2205 if (!strncmp(d->exec, "steam ", 6))
2206 {
2207 const char *st = strstr(d->exec, "steam://rungameid/");
2208 if (st)
2209 {
2210 st += strlen("steam://rungameid/");
2211 unsigned int id = atoi(st);
2212 if (id == ec->steam.steam_game_id)
2213 ec->desktop = d;
2214 }
2215 }
2216 }
2217 }
2218 }
2219 if (!ec->desktop)
2220 {
2221 E_Exec_Instance *inst;
2222
2223 inst = e_exec_startup_id_pid_instance_find(ec->netwm.startup_id,
2224 ec->netwm.pid);
2225 if (inst && inst->clients)
2226 {
2227 E_Client *ec2 = eina_list_data_get(inst->clients);
2228
2229 if (ec2->netwm.pid == ec->netwm.pid)
2230 ec->desktop = inst->desktop;
2231 }
2232 else if (inst)
2233 ec->desktop = inst->desktop;
2234 if (ec->desktop) efreet_desktop_ref(ec->desktop);
2235 }
2236 if (!ec->desktop)
2237 {
2238 if (ec->internal && (ec->icccm.class && (!strncmp(ec->icccm.class, "e_fwin::", 8))))
2239 ec->desktop = efreet_util_desktop_exec_find("enlightenment_filemanager");
2240 }
2241 if (!ec->desktop)
2242 {
2243 if ((ec->icccm.name) || (ec->icccm.class))
2244 ec->desktop = efreet_util_desktop_wm_class_find(ec->icccm.name,
2245 ec->icccm.class);
2246 }
2247 if (!ec->desktop && ec->icccm.command.argv && (ec->icccm.command.argc > 0))
2248 {
2249 ec->desktop = efreet_util_desktop_exec_find(ec->icccm.command.argv[0]);
2250 }
2251 if (!ec->desktop)
2252 {
2253 // special case hacks for specific apps that just don't do things
2254 // right so we have to work around them
2255 if (ec->icccm.class && ec->icccm.name &&
2256 (!strcmp(ec->icccm.class, "Steam")) &&
2257 (!strcmp(ec->icccm.name, "Steam")))
2258 {
2259 ec->desktop = efreet_util_desktop_file_id_find("steam.desktop");
2260 }
2261 /* libreoffice and maybe others match window class
2262 with .desktop file name */
2263 else if (ec->icccm.class)
2264 {
2265 char buf[4096] = {0};
2266 snprintf(buf, sizeof(buf), "%s.desktop", ec->icccm.class);
2267 ec->desktop = efreet_util_desktop_file_id_find(buf);
2268 if (!ec->desktop)
2269 {
2270 char *s;
2271
2272 strncpy(buf, ec->icccm.class, sizeof(buf) - 1);
2273 s = buf;
2274 eina_str_tolower(&s);
2275 if (strcmp(s, ec->icccm.class))
2276 ec->desktop = efreet_util_desktop_exec_find(s);
2277 }
2278 }
2279 }
2280 if (!ec->desktop && ec->icccm.name)
2281 {
2282 /* this works for most cases as fallback. useful when app is
2283 run from a shell */
2284 ec->desktop = efreet_util_desktop_exec_find(ec->icccm.name);
2285 }
2286 if (!ec->desktop && ec->parent)
2287 {
2288 E_Client *ec2 = ec->parent;
2289 if (ec2->desktop)
2290 {
2291 efreet_desktop_ref(ec2->desktop);
2292 ec->desktop = ec2->desktop;
2293 }
2294 }
2295
2296 if (ec->desktop)
2297 {
2298 if (!ec->exe_inst)
2299 e_exec_phony(ec);
2300 if (!ec->exe_inst->desktop)
2301 {
2302 efreet_desktop_ref(ec->desktop);
2303 ec->exe_inst->desktop = ec->desktop;
2304 }
2305 }
2306 ec->changes.icon = !e_comp_object_frame_icon_update(ec->frame);
2307 prop |= E_CLIENT_PROPERTY_ICON;
2308 }
2309
2310 if (ec->new_client)
2311 e_comp->new_clients--;
2312 ec->new_client = 0;
2313 ec->changed = ec->changes.pos || ec->changes.size ||
2314 ec->changes.stack || ec->changes.prop || ec->changes.border ||
2315 ec->changes.reset_gravity || ec->changes.shading || ec->changes.shaded ||
2316 ec->changes.shape || ec->changes.shape_input || ec->changes.icon ||
2317 ec->changes.internal_state ||
2318 ec->changes.need_maximize || ec->changes.need_unmaximize;
2319 ec->changes.stack = 0;
2320
2321 if ((!ec->input_only) && (!ec->iconic) &&
2322 ((!ec->zone) || e_client_util_desk_visible(ec, e_desk_current_get(ec->zone))) &&
2323 ((ec->take_focus) || (ec->want_focus)))
2324 {
2325 ec->take_focus = 0;
2326 if ((ec->stack.prev) && (!ec->stack.next) &&
2327 (ec->stack.prev == e_client_focused_get()))
2328 {
2329 e_client_focus_set_with_pointer(ec);
2330 }
2331 else if ((e_config->focus_setting == E_FOCUS_NEW_WINDOW) || (ec->want_focus))
2332 {
2333 ec->want_focus = 0;
2334 e_client_focus_set_with_pointer(ec);
2335 }
2336 else if (ec->dialog)
2337 {
2338 if ((e_config->focus_setting == E_FOCUS_NEW_DIALOG) ||
2339 ((e_config->focus_setting == E_FOCUS_NEW_DIALOG_IF_OWNER_FOCUSED) &&
2340 (ec->parent == e_client_focused_get())))
2341 {
2342 e_client_focus_set_with_pointer(ec);
2343 }
2344 }
2345 else
2346 {
2347 /* focus window by default when it is the only one on desk */
2348 E_Client *ec2 = NULL;
2349 Eina_List *l;
2350 EINA_LIST_FOREACH(focus_stack, l, ec2)
2351 {
2352 if (ec == ec2) continue;
2353 if ((!ec2->iconic) && (ec2->visible) &&
2354 ((ec->desk == ec2->desk) || ec2->sticky))
2355 break;
2356 }
2357
2358 if (!ec2)
2359 {
2360 e_client_focus_set_with_pointer(ec);
2361 }
2362 }
2363 }
2364 else
2365 ec->take_focus = ec->want_focus = 0;
2366
2367 if (ec->changes.need_maximize)
2368 {
2369 E_Maximize max = ec->maximized;
2370 ec->maximized = E_MAXIMIZE_NONE;
2371 e_client_maximize(ec, max);
2372 ec->changes.need_maximize = 0;
2373 }
2374 else if (ec->changes.need_unmaximize)
2375 {
2376 e_client_unmaximize(ec, ec->maximized);
2377 ec->changes.need_unmaximize = 0;
2378 }
2379
2380 if (ec->need_fullscreen)
2381 {
2382 e_client_fullscreen(ec, e_config->fullscreen_policy);
2383 ec->need_fullscreen = 0;
2384 }
2385
2386 if (rem_change)
2387 e_remember_update(ec);
2388
2389 if (send_event && rem_change && prop)
2390 {
2391 _e_client_event_property(ec, prop);
2392 }
2393 _e_client_hook_call(E_CLIENT_HOOK_EVAL_END, ec);
2394 }
2395
2396 static void
_e_client_frame_update(E_Client * ec)2397 _e_client_frame_update(E_Client *ec)
2398 {
2399 const char *bordername;
2400
2401 ec->border.changed = 0;
2402 if ((!e_comp_object_frame_allowed(ec->frame)) && (!e_comp_object_frame_exists(ec->frame)))
2403 return;
2404 if (ec->fullscreen || ec->borderless)
2405 bordername = "borderless";
2406 else if (ec->bordername)
2407 bordername = ec->bordername;
2408 else if (ec->mwm.borderless)
2409 bordername = "borderless";
2410 else if (((ec->icccm.transient_for != 0) || (ec->dialog)) &&
2411 (ec->icccm.min_w == ec->icccm.max_w) &&
2412 (ec->icccm.min_h == ec->icccm.max_h))
2413 bordername = "noresize_dialog";
2414 else if ((ec->icccm.min_w == ec->icccm.max_w) &&
2415 (ec->icccm.min_h == ec->icccm.max_h))
2416 bordername = "noresize";
2417 else if (ec->shaped)
2418 bordername = "shaped";
2419 else if (e_pixmap_is_x(ec->pixmap) &&
2420 ((!ec->icccm.accepts_focus) &&
2421 (!ec->icccm.take_focus)))
2422 bordername = "nofocus";
2423 else if (ec->urgent)
2424 bordername = "urgent";
2425 else if (((ec->icccm.transient_for && (!ec->netwm.type)) || (ec->dialog)) &&
2426 (e_pixmap_is_x(ec->pixmap)))
2427 bordername = "dialog";
2428 else if (ec->netwm.state.modal)
2429 bordername = "modal";
2430 else if ((ec->netwm.state.skip_taskbar) ||
2431 (ec->netwm.state.skip_pager))
2432 bordername = "skipped";
2433 /*
2434 else if ((ec->internal) && (ec->icccm.class) &&
2435 (!strncmp(ec->icccm.class, "e_fwin", 6)))
2436 bordername = "internal_fileman";
2437 */
2438 else
2439 bordername = e_config->theme_default_border_style;
2440 if (!bordername) bordername = "default";
2441
2442 e_client_border_set(ec, bordername);
2443 }
2444
2445 ////////////////////////////////////////////////
2446 EINTERN void
e_client_idler_before(void)2447 e_client_idler_before(void)
2448 {
2449 const Eina_List *l;
2450 E_Client *ec;
2451
2452 if ((!eina_hash_population(clients_hash[0])) && (!eina_hash_population(clients_hash[1]))) return;
2453
2454 EINA_LIST_FOREACH(e_comp->clients, l, ec)
2455 {
2456 Eina_Stringshare *title;
2457 // pass 1 - eval0. fetch properties on new or on change and
2458 // call hooks to decide what to do - maybe move/resize
2459 if (ec->ignored || (!ec->changed)) continue;
2460
2461 if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_PRE_FETCH, ec)) continue;
2462 /* FETCH is hooked by the compositor to get client hints */
2463 title = e_client_util_name_get(ec);
2464 if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_FETCH, ec)) continue;
2465 if (title != e_client_util_name_get(ec))
2466 _e_client_event_property(ec, E_CLIENT_PROPERTY_TITLE);
2467 /* PRE_POST_FETCH calls e_remember apply for new client */
2468 if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_PRE_POST_FETCH, ec)) continue;
2469 if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_POST_FETCH, ec)) continue;
2470 if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_PRE_FRAME_ASSIGN, ec)) continue;
2471
2472 if ((ec->border.changed) && (!ec->shaded) && (!e_client_is_stacking(ec)) &&
2473 ((!ec->override) || ec->internal) &&
2474 (!(((ec->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_FULLSCREEN))))
2475 _e_client_frame_update(ec);
2476 ec->border.changed = 0;
2477 _e_client_hook_call(E_CLIENT_HOOK_EVAL_POST_FRAME_ASSIGN, ec);
2478 }
2479
2480 E_CLIENT_FOREACH(ec)
2481 {
2482 if (ec->ignored) continue;
2483 // pass 2 - show windows needing show
2484 if ((ec->changes.visible) && (ec->visible) &&
2485 (!ec->new_client) && (!ec->changes.pos) &&
2486 (!ec->changes.size))
2487 {
2488 evas_object_show(ec->frame);
2489 ec->changes.visible = !evas_object_visible_get(ec->frame);
2490 }
2491
2492 if ((!ec->new_client) && (!e_client_util_ignored_get(ec)) &&
2493 (!E_INSIDE(ec->x, ec->y, 0, 0, e_comp->w - 5, e_comp->h - 5)) &&
2494 (!E_INSIDE(ec->x, ec->y, 0 - ec->w + 5, 0 - ec->h + 5, e_comp->w - 5, e_comp->h - 5))
2495 )
2496 {
2497 if (e_config->screen_limits != E_CLIENT_OFFSCREEN_LIMIT_ALLOW_FULL)
2498 {
2499 if (ec->parent)
2500 e_comp_object_util_center_on(ec->frame, ec->parent->frame);
2501 else
2502 _e_client_move_lost_window_to_center(ec);
2503 }
2504 }
2505 // handle window stack
2506 if (!ec->stack.prev && ec->stack.next)
2507 {
2508 if (ec->stack.ignore == 0)
2509 {
2510 Eina_List *ll, *list = e_client_stack_list_prepare(ec);
2511 E_Client *child, *bottom, *moving = NULL, *rel;
2512 int x, y;
2513
2514 bottom = rel = e_client_stack_bottom_get(ec);
2515 EINA_LIST_FOREACH(list, ll, child)
2516 {
2517 if (child->moving)
2518 {
2519 moving = child;
2520 break;
2521 }
2522 }
2523 if (moving)
2524 {
2525 Evas_Coord ox, oy;
2526
2527 evas_object_geometry_get(ec->frame, &ox, &oy, NULL, NULL);
2528 rel = moving;
2529 }
2530 EINA_LIST_FOREACH(list, ll, child)
2531 {
2532 if (moving)
2533 {
2534 if (child == moving) continue;
2535 }
2536 else if (child == bottom) continue;
2537 x = rel->x + ((rel->w - child->w) / 2);
2538 y = rel->y + ((rel->h - child->h) / 2);
2539 if ((x != child->x) || (y != child->y))
2540 {
2541 child->x = x;
2542 child->y = y;
2543 child->pre_cb.x = x;
2544 child->pre_cb.y = y;
2545 child->changes.pos = 1;
2546 child->changed = 1;
2547 }
2548 }
2549 e_client_stack_list_finish(list);
2550 }
2551 }
2552 }
2553
2554 if (_e_client_layout_cb)
2555 _e_client_layout_cb();
2556
2557 // pass 3 - hide windows needing hide and eval (main eval)
2558 E_CLIENT_FOREACH(ec)
2559 {
2560 if (ec->ignored || e_object_is_del(E_OBJECT(ec))) continue;
2561
2562 if ((ec->changes.visible) && (!ec->visible))
2563 {
2564 evas_object_hide(ec->frame);
2565 ec->changes.visible = 0;
2566 }
2567
2568 if (ec->changed)
2569 _e_client_eval(ec);
2570
2571 if ((ec->changes.visible) && (ec->visible) && (!ec->changed))
2572 {
2573 evas_object_show(ec->frame);
2574 ec->changes.visible = !evas_object_visible_get(ec->frame);
2575 if (ec->changes.visible) EC_CHANGED(ec);
2576 if (!e_client_util_desk_visible(ec, e_desk_current_get(ec->zone)))
2577 evas_object_hide(ec->frame);
2578 }
2579 }
2580 }
2581
2582
2583 EINTERN Eina_Bool
e_client_init(void)2584 e_client_init(void)
2585 {
2586 clients_hash[0] = eina_hash_pointer_new(NULL);
2587 clients_hash[1] = eina_hash_pointer_new(NULL);
2588
2589 E_LIST_HANDLER_APPEND(handlers, E_EVENT_POINTER_WARP,
2590 _e_client_cb_pointer_warp, NULL);
2591 E_LIST_HANDLER_APPEND(handlers, EFREET_EVENT_DESKTOP_CACHE_UPDATE,
2592 _e_client_cb_efreet_cache_update, NULL);
2593 E_LIST_HANDLER_APPEND(handlers, EFREET_EVENT_ICON_CACHE_UPDATE,
2594 _e_client_cb_efreet_cache_update, NULL);
2595 E_LIST_HANDLER_APPEND(handlers, E_EVENT_CONFIG_ICON_THEME,
2596 _e_client_cb_config_icon_theme, NULL);
2597 E_LIST_HANDLER_APPEND(handlers, E_EVENT_CONFIG_MODE_CHANGED,
2598 _e_client_cb_config_mode, NULL);
2599 E_LIST_HANDLER_APPEND(handlers, E_EVENT_DESK_WINDOW_PROFILE_CHANGE,
2600 _e_client_cb_desk_window_profile_change, NULL);
2601
2602 E_EVENT_CLIENT_ADD = ecore_event_type_new();
2603 E_EVENT_CLIENT_REMOVE = ecore_event_type_new();
2604 E_EVENT_CLIENT_DESK_SET = ecore_event_type_new();
2605 E_EVENT_CLIENT_ZONE_SET = ecore_event_type_new();
2606 E_EVENT_CLIENT_RESIZE = ecore_event_type_new();
2607 E_EVENT_CLIENT_MOVE = ecore_event_type_new();
2608 E_EVENT_CLIENT_SHOW = ecore_event_type_new();
2609 E_EVENT_CLIENT_HIDE = ecore_event_type_new();
2610 E_EVENT_CLIENT_ICONIFY = ecore_event_type_new();
2611 E_EVENT_CLIENT_UNICONIFY = ecore_event_type_new();
2612 E_EVENT_CLIENT_STACK = ecore_event_type_new();
2613 E_EVENT_CLIENT_FOCUS_IN = ecore_event_type_new();
2614 E_EVENT_CLIENT_FOCUS_OUT = ecore_event_type_new();
2615 E_EVENT_CLIENT_PROPERTY = ecore_event_type_new();
2616 E_EVENT_CLIENT_FULLSCREEN = ecore_event_type_new();
2617 E_EVENT_CLIENT_UNFULLSCREEN = ecore_event_type_new();
2618
2619 return (!!clients_hash[1]);
2620 }
2621
2622 EINTERN void
e_client_shutdown(void)2623 e_client_shutdown(void)
2624 {
2625 E_FREE_FUNC(clients_hash[0], eina_hash_free);
2626 E_FREE_FUNC(clients_hash[1], eina_hash_free);
2627
2628 E_FREE_LIST(handlers, ecore_event_handler_del);
2629
2630 e_int_client_menu_hooks_clear();
2631 E_FREE_FUNC(warp_timer, ecore_timer_del);
2632 warp_client = NULL;
2633 }
2634
2635 E_API void
e_client_unignore(E_Client * ec)2636 e_client_unignore(E_Client *ec)
2637 {
2638 E_OBJECT_CHECK(ec);
2639 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
2640 if (!ec->ignored) return;
2641
2642 ec->ignored = 0;
2643 if (!e_client_util_ignored_get(ec))
2644 {
2645 if (starting)
2646 focus_stack = eina_list_prepend(focus_stack, ec);
2647 else
2648 focus_stack = eina_list_append(focus_stack, ec);
2649 }
2650 _e_client_event_simple(ec, E_EVENT_CLIENT_ADD);
2651 _e_client_hook_call(E_CLIENT_HOOK_UNIGNORE, ec);
2652 }
2653
2654 E_API E_Client *
e_client_new(E_Pixmap * cp,int first_map,int internal)2655 e_client_new(E_Pixmap *cp, int first_map, int internal)
2656 {
2657 E_Client *ec;
2658 E_Pixmap_Type ptype = e_pixmap_type_get(cp);
2659
2660 if ((ptype != E_PIXMAP_TYPE_X) && (ptype != E_PIXMAP_TYPE_WL)) return NULL;
2661 if (eina_hash_find(clients_hash[ptype], &cp)) return NULL;
2662
2663 ec = E_OBJECT_ALLOC(E_Client, E_CLIENT_TYPE, _e_client_free);
2664 if (!ec) return NULL;
2665 e_object_del_func_set(E_OBJECT(ec), E_OBJECT_CLEANUP_FUNC(_e_client_del));
2666
2667 ec->focus_policy_override = E_FOCUS_LAST;
2668 ec->w = 1;
2669 ec->h = 1;
2670 ec->internal = internal;
2671
2672 ec->pixmap = cp;
2673 e_pixmap_client_set(cp, ec);
2674 ec->resize_mode = E_POINTER_RESIZE_NONE;
2675 ec->layer = E_LAYER_CLIENT_NORMAL;
2676
2677 /* printf("##- ON MAP CLIENT 0x%x SIZE %ix%i %i:%i\n",
2678 * ec->win, ec->w, ec->h, att->x, att->y); */
2679
2680 /* FIXME: if first_map is 1 then we should ignore the first hide event
2681 * or ensure the window is already hidden and events flushed before we
2682 * create a border for it */
2683 if (first_map)
2684 {
2685 // printf("##- FIRST MAP\n");
2686 ec->re_manage = 1;
2687 // needed to be 1 for internal windw and on restart.
2688 // ec->ignore_first_unmap = 2;
2689 }
2690 ec->offer_resistance = 1;
2691 ec->new_client = 1;
2692 e_comp->new_clients++;
2693
2694 if (!_e_client_hook_call(E_CLIENT_HOOK_NEW_CLIENT, ec))
2695 {
2696 /* delete the above allocated object */
2697 //e_object_del(E_OBJECT(ec));
2698 return NULL;
2699 }
2700
2701 ec->icccm.title = NULL;
2702 ec->icccm.name = NULL;
2703 ec->icccm.class = NULL;
2704 ec->icccm.icon_name = NULL;
2705 ec->icccm.machine = NULL;
2706 ec->icccm.min_w = 1;
2707 ec->icccm.min_h = 1;
2708 ec->icccm.max_w = 32767;
2709 ec->icccm.max_h = 32767;
2710 ec->icccm.base_w = 0;
2711 ec->icccm.base_h = 0;
2712 ec->icccm.step_w = -1;
2713 ec->icccm.step_h = -1;
2714 ec->icccm.min_aspect = 0.0;
2715 ec->icccm.max_aspect = 0.0;
2716
2717 ec->netwm.pid = 0;
2718 ec->netwm.name = NULL;
2719 ec->netwm.icon_name = NULL;
2720 ec->netwm.desktop = 0;
2721 ec->netwm.state.modal = 0;
2722 ec->netwm.state.sticky = 0;
2723 ec->netwm.state.shaded = 0;
2724 ec->netwm.state.hidden = 0;
2725 ec->netwm.state.maximized_v = 0;
2726 ec->netwm.state.maximized_h = 0;
2727 ec->netwm.state.skip_taskbar = 0;
2728 ec->netwm.state.skip_pager = 0;
2729 ec->netwm.state.fullscreen = 0;
2730 ec->netwm.state.stacking = E_STACKING_NONE;
2731 ec->netwm.action.move = 0;
2732 ec->netwm.action.resize = 0;
2733 ec->netwm.action.minimize = 0;
2734 ec->netwm.action.shade = 0;
2735 ec->netwm.action.stick = 0;
2736 ec->netwm.action.maximized_h = 0;
2737 ec->netwm.action.maximized_v = 0;
2738 ec->netwm.action.fullscreen = 0;
2739 ec->netwm.action.change_desktop = 0;
2740 ec->netwm.action.close = 0;
2741 ec->netwm.opacity = 255;
2742
2743 e_comp->clients = eina_list_append(e_comp->clients, ec);
2744 eina_hash_add(clients_hash[ptype], &ec->pixmap, ec);
2745
2746 if (!ec->ignored) EC_CHANGED(ec);
2747
2748 e_comp_object_client_add(ec);
2749
2750 if (ec->override)
2751 _e_client_zone_update(ec);
2752 else if (!ec->desk)
2753 e_client_desk_set(ec, e_desk_current_get(e_zone_current_get()));
2754 if (!ec->re_manage)
2755 ec->placed = ec->changes.pos = 0; //ensure placement is run
2756 if (ec->frame)
2757 {
2758 evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_SHOW, _e_client_cb_evas_show, ec);
2759 evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_HIDE, _e_client_cb_evas_hide, ec);
2760 evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_MOVE, _e_client_cb_evas_move, ec);
2761 evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_RESIZE, _e_client_cb_evas_resize, ec);
2762 evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_RESTACK, _e_client_cb_evas_restack, ec);
2763 evas_object_smart_callback_add(ec->frame, "shade_done", _e_client_cb_evas_shade_done, ec);
2764 if (ec->override)
2765 evas_object_layer_set(ec->frame, E_LAYER_CLIENT_ABOVE);
2766 else
2767 evas_object_layer_set(ec->frame, E_LAYER_CLIENT_NORMAL);
2768 }
2769 if (!e_client_util_ignored_get(ec))
2770 {
2771 if (starting)
2772 focus_stack = eina_list_prepend(focus_stack, ec);
2773 else
2774 focus_stack = eina_list_append(focus_stack, ec);
2775 }
2776
2777 e_hints_client_list_set();
2778 return ec;
2779 }
2780
2781 E_API Eina_Bool
e_client_desk_window_profile_available_check(E_Client * ec,const char * profile)2782 e_client_desk_window_profile_available_check(E_Client *ec, const char *profile)
2783 {
2784 int i;
2785
2786 E_OBJECT_CHECK_RETURN(ec, EINA_FALSE);
2787 E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, EINA_FALSE);
2788 EINA_SAFETY_ON_NULL_RETURN_VAL(profile, EINA_FALSE);
2789 EINA_SAFETY_ON_FALSE_RETURN_VAL(ec->e.state.profile.use, EINA_FALSE);
2790 if (ec->e.state.profile.num == 0) return EINA_TRUE;
2791
2792 for (i = 0; i < ec->e.state.profile.num; i++)
2793 {
2794 if (!e_util_strcmp(ec->e.state.profile.available_list[i],
2795 profile))
2796 return EINA_TRUE;
2797 }
2798
2799 return EINA_FALSE;
2800 }
2801
2802 E_API void
e_client_desk_window_profile_wait_desk_set(E_Client * ec,E_Desk * desk)2803 e_client_desk_window_profile_wait_desk_set(E_Client *ec, E_Desk *desk)
2804 {
2805 E_OBJECT_CHECK(ec);
2806 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
2807 E_OBJECT_CHECK(desk);
2808 E_OBJECT_TYPE_CHECK(desk, E_DESK_TYPE);
2809
2810 if (ec->e.state.profile.wait_desk == desk) return;
2811
2812 if (ec->e.state.profile.wait_desk_delfn)
2813 {
2814 if (ec->e.state.profile.wait_desk)
2815 e_object_delfn_del(E_OBJECT(ec->e.state.profile.wait_desk),
2816 ec->e.state.profile.wait_desk_delfn);
2817 ec->e.state.profile.wait_desk_delfn = NULL;
2818 }
2819
2820 if (ec->e.state.profile.wait_desk)
2821 e_object_unref(E_OBJECT(ec->e.state.profile.wait_desk));
2822 ec->e.state.profile.wait_desk = NULL;
2823
2824 if (desk)
2825 {
2826 ec->e.state.profile.wait_desk_delfn =
2827 e_object_delfn_add(E_OBJECT(desk),
2828 _e_client_desk_window_profile_wait_desk_delfn,
2829 ec);
2830 }
2831 ec->e.state.profile.wait_desk = desk;
2832 if (ec->e.state.profile.wait_desk)
2833 e_object_ref(E_OBJECT(ec->e.state.profile.wait_desk));
2834 }
2835
2836 E_API void
e_client_desk_set(E_Client * ec,E_Desk * desk)2837 e_client_desk_set(E_Client *ec, E_Desk *desk)
2838 {
2839 E_Event_Client_Desk_Set *ev;
2840 E_Desk *old_desk;
2841
2842 E_OBJECT_CHECK(ec);
2843 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
2844 E_OBJECT_CHECK(desk);
2845 E_OBJECT_TYPE_CHECK(desk, E_DESK_TYPE);
2846 if (ec->desk == desk) return;
2847 if (ec->e.state.profile.use)
2848 {
2849 const char *profile = desk->window_profile;
2850
2851 if (!profile) profile = elm_config_profile_get();
2852 if (!profile) profile = "standard";
2853 if (e_util_strcmp(ec->e.state.profile.name, profile))
2854 {
2855 if (e_client_desk_window_profile_available_check(ec, profile))
2856 {
2857 eina_stringshare_replace(&ec->e.state.profile.set, profile);
2858 eina_stringshare_replace(&ec->e.state.profile.wait, NULL);
2859 ec->e.state.profile.wait_for_done = 0;
2860 e_client_desk_window_profile_wait_desk_set(ec, desk);
2861 EC_CHANGED(ec);
2862 }
2863 }
2864 }
2865
2866 if (ec->fullscreen)
2867 {
2868 if (ec->desk)
2869 ec->desk->fullscreen_clients = eina_list_remove(ec->desk->fullscreen_clients, ec);
2870 desk->fullscreen_clients = eina_list_append(desk->fullscreen_clients, ec);
2871 }
2872 old_desk = ec->desk;
2873 ec->desk = desk;
2874 if (ec->frame)
2875 {
2876 e_comp_object_effect_unclip(ec->frame);
2877 e_comp_object_effect_set(ec->frame, NULL);
2878 }
2879 if (desk->visible || ec->sticky)
2880 {
2881 // force visibility if its a stack window going onto this desktop
2882 if (ec->stack.prev || ec->stack.next) ec->hidden = 0;
2883 if ((!ec->hidden) && (!ec->iconic))
2884 evas_object_show(ec->frame);
2885 }
2886 else
2887 {
2888 ec->hidden = 1;
2889 evas_object_hide(ec->frame);
2890 }
2891 e_client_comp_hidden_set(ec, (!desk->visible) && (!ec->sticky));
2892 e_client_zone_set(ec, desk->zone);
2893
2894 e_hints_window_desktop_set(ec);
2895
2896 if (old_desk)
2897 {
2898 ev = E_NEW(E_Event_Client_Desk_Set, 1);
2899 ev->ec = ec;
2900 UNREFD(ec, 4);
2901 e_object_ref(E_OBJECT(ec));
2902 ev->desk = old_desk;
2903 e_object_ref(E_OBJECT(old_desk));
2904 ecore_event_add(E_EVENT_CLIENT_DESK_SET, ev, (Ecore_End_Cb)_e_client_event_desk_set_free, NULL);
2905
2906 if (old_desk->zone == ec->zone)
2907 {
2908 if (ec->maximized || ec->fullscreen)
2909 e_client_rescale(ec);
2910 }
2911 }
2912
2913 if (ec->stack.prev || ec->stack.next)
2914 {
2915 if (ec->stack.ignore == 0)
2916 {
2917 Eina_List *l, *list = e_client_stack_list_prepare(ec);
2918 E_Client *child;
2919
2920 EINA_LIST_FOREACH(list, l, child)
2921 {
2922 if (child == ec) break;
2923 e_client_desk_set(child, ec->desk);
2924 evas_object_stack_below(child->frame, ec->frame);
2925 }
2926 EINA_LIST_REVERSE_FOREACH(list, l, child)
2927 {
2928 if (child == ec) break;
2929 e_client_desk_set(child, ec->desk);
2930 evas_object_stack_above(child->frame, ec->frame);
2931 }
2932 e_client_stack_list_finish(list);
2933 }
2934 }
2935 else
2936 {
2937 if (e_config->transient.desktop)
2938 {
2939 E_Client *child;
2940 const Eina_List *l;
2941
2942 EINA_LIST_FOREACH(ec->transients, l, child)
2943 e_client_desk_set(child, ec->desk);
2944 e_client_transients_restack(ec);
2945 }
2946 }
2947
2948 e_remember_update(ec);
2949 _e_client_hook_call(E_CLIENT_HOOK_DESK_SET, ec);
2950 evas_object_smart_callback_call(ec->frame, "desk_change", ec);
2951 }
2952
2953 E_API Eina_Bool
e_client_comp_grabbed_get(void)2954 e_client_comp_grabbed_get(void)
2955 {
2956 return comp_grabbed;
2957 }
2958
2959 E_API E_Client *
e_client_action_get(void)2960 e_client_action_get(void)
2961 {
2962 return action_client;
2963 }
2964
2965 E_API E_Client *
e_client_warping_get(void)2966 e_client_warping_get(void)
2967 {
2968 return warp_client;
2969 }
2970
2971
2972 E_API Eina_List *
e_clients_immortal_list(void)2973 e_clients_immortal_list(void)
2974 {
2975 const Eina_List *l;
2976 Eina_List *list = NULL;
2977 E_Client *ec;
2978
2979 EINA_LIST_FOREACH(e_comp->clients, l, ec)
2980 {
2981 if (ec->lock_life)
2982 list = eina_list_append(list, ec);
2983 }
2984 return list;
2985 }
2986
2987 //////////////////////////////////////////////////////////
2988
2989 E_API void
e_client_mouse_in(E_Client * ec,int x,int y)2990 e_client_mouse_in(E_Client *ec, int x, int y)
2991 {
2992 if (comp_grabbed) return;
2993 if (warp_client && (ec != warp_client)) return;
2994 if (e_object_is_del(E_OBJECT(ec))) return;
2995 if (ec->desk && ec->desk->animate_count) return;
2996 ec->mouse.current.mx = x;
2997 ec->mouse.current.my = y;
2998 ec->mouse.in = 1;
2999 if ((!ec->iconic) && (!e_client_util_ignored_get(ec)))
3000 e_focus_event_mouse_in(ec);
3001 }
3002
3003 E_API void
e_client_mouse_out(E_Client * ec,int x,int y)3004 e_client_mouse_out(E_Client *ec, int x, int y)
3005 {
3006 if (comp_grabbed) return;
3007 if (ec->desk && ec->desk->animate_count) return;
3008 if (e_pixmap_is_x(ec->pixmap) && E_INSIDE(x, y, ec->x, ec->y, ec->w, ec->h)) return;
3009
3010 ec->mouse.current.mx = x;
3011 ec->mouse.current.my = y;
3012 ec->mouse.in = 0;
3013 if (ec->fullscreen) return;
3014 if (e_object_is_del(E_OBJECT(ec))) return;
3015 if ((!ec->iconic) && (!e_client_util_ignored_get(ec)))
3016 e_focus_event_mouse_out(ec);
3017 }
3018
3019 E_API void
e_client_mouse_wheel(E_Client * ec,Evas_Point * output,E_Binding_Event_Wheel * ev)3020 e_client_mouse_wheel(E_Client *ec, Evas_Point *output, E_Binding_Event_Wheel *ev)
3021 {
3022 EINA_SAFETY_ON_NULL_RETURN(ec);
3023 if (action_client) return;
3024 ec->mouse.current.mx = output->x;
3025 ec->mouse.current.my = output->y;
3026 if ((!ec->cur_mouse_action) && (!e_client_util_ignored_get(ec)))
3027 e_bindings_wheel_event_handle(E_BINDING_CONTEXT_WINDOW, E_OBJECT(ec), ev);
3028 }
3029
3030 E_API void
e_client_mouse_down(E_Client * ec,int button,Evas_Point * output,E_Binding_Event_Mouse_Button * ev)3031 e_client_mouse_down(E_Client *ec, int button, Evas_Point *output, E_Binding_Event_Mouse_Button *ev)
3032 {
3033 Eina_Bool did_act = EINA_FALSE;
3034 E_Client *pfocus;
3035 int player;
3036
3037 EINA_SAFETY_ON_NULL_RETURN(ec);
3038 if (action_client || ec->iconic || e_client_util_ignored_get(ec)) return;
3039 if ((button >= 1) && (button <= 3))
3040 {
3041 ec->mouse.last_down[button - 1].mx = output->x;
3042 ec->mouse.last_down[button - 1].my = output->y;
3043 ec->mouse.last_down[button - 1].x = ec->x;
3044 ec->mouse.last_down[button - 1].y = ec->y;
3045 ec->mouse.last_down[button - 1].w = ec->w;
3046 ec->mouse.last_down[button - 1].h = ec->h;
3047 }
3048 else
3049 {
3050 ec->moveinfo.down.x = ec->x;
3051 ec->moveinfo.down.y = ec->y;
3052 ec->moveinfo.down.w = ec->w;
3053 ec->moveinfo.down.h = ec->h;
3054 }
3055 ec->mouse.current.mx = output->x;
3056 ec->mouse.current.my = output->y;
3057 pfocus = e_client_focused_get();
3058 player = ec->layer;
3059 if (!ec->cur_mouse_action)
3060 {
3061 ec->cur_mouse_action =
3062 e_bindings_mouse_down_event_handle(E_BINDING_CONTEXT_WINDOW,
3063 E_OBJECT(ec), ev);
3064 if (ec->next_mouse_action_ignore)
3065 ec->cur_mouse_action = NULL;
3066 if (ec->cur_mouse_action)
3067 {
3068 did_act = EINA_TRUE;
3069 e_object_ref(E_OBJECT(ec->cur_mouse_action));
3070 if (ec->internal)
3071 {
3072 int button_mask, i;
3073 Evas *e;
3074
3075 e = evas_object_evas_get(ec->internal_elm_win);
3076 button_mask = evas_pointer_button_down_mask_get(e);
3077 for (i = 0; i < 32; i++)
3078 {
3079 if ((button_mask & (1 << i)))
3080 evas_event_feed_mouse_up(e, i + 1, EVAS_BUTTON_NONE, 0, NULL);
3081 }
3082 evas_event_feed_mouse_out(e, 0, NULL);
3083 }
3084 }
3085 }
3086 if ((!did_act) || (((pfocus == e_client_focused_get()) || (ec == e_client_focused_get())) && (ec->layer >= player)))
3087 e_focus_event_mouse_down(ec);
3088 if ((button >= 1) && (button <= 3))
3089 {
3090 ec->mouse.last_down[button - 1].mx = output->x;
3091 ec->mouse.last_down[button - 1].my = output->y;
3092 ec->mouse.last_down[button - 1].x = ec->x;
3093 ec->mouse.last_down[button - 1].y = ec->y;
3094 ec->mouse.last_down[button - 1].w = ec->w;
3095 ec->mouse.last_down[button - 1].h = ec->h;
3096 }
3097 else
3098 {
3099 ec->moveinfo.down.x = ec->x;
3100 ec->moveinfo.down.y = ec->y;
3101 ec->moveinfo.down.w = ec->w;
3102 ec->moveinfo.down.h = ec->h;
3103 }
3104 ec->mouse.current.mx = output->x;
3105 ec->mouse.current.my = output->y;
3106 }
3107
3108 E_API void
e_client_mouse_up(E_Client * ec,int button,Evas_Point * output,E_Binding_Event_Mouse_Button * ev)3109 e_client_mouse_up(E_Client *ec, int button, Evas_Point *output, E_Binding_Event_Mouse_Button* ev)
3110 {
3111 EINA_SAFETY_ON_NULL_RETURN(ec);
3112 if (ec->iconic || e_client_util_ignored_get(ec)) return;
3113 if ((button >= 1) && (button <= 3))
3114 {
3115 ec->mouse.last_up[button - 1].mx = output->x;
3116 ec->mouse.last_up[button - 1].my = output->y;
3117 ec->mouse.last_up[button - 1].x = ec->x;
3118 ec->mouse.last_up[button - 1].y = ec->y;
3119 }
3120 ec->mouse.current.mx = output->x;
3121 ec->mouse.current.my = output->y;
3122 /* also we don't pass the same params that went in - then again that */
3123 /* should be ok as we are just ending the action if it has an end */
3124 if (ec->cur_mouse_action)
3125 _e_client_mouse_action_end(ec);
3126 else
3127 {
3128 if (!e_bindings_mouse_up_event_handle(E_BINDING_CONTEXT_WINDOW, E_OBJECT(ec), ev))
3129 e_focus_event_mouse_up(ec);
3130 }
3131 if ((button >= 1) && (button <= 3))
3132 {
3133 ec->mouse.last_up[button - 1].mx = output->x;
3134 ec->mouse.last_up[button - 1].my = output->y;
3135 ec->mouse.last_up[button - 1].x = ec->x;
3136 ec->mouse.last_up[button - 1].y = ec->y;
3137 }
3138
3139 ec->drag.start = 0;
3140 }
3141
3142 E_API void
e_client_mouse_move(E_Client * ec,Evas_Point * output)3143 e_client_mouse_move(E_Client *ec, Evas_Point *output)
3144 {
3145 EINA_SAFETY_ON_NULL_RETURN(ec);
3146 if (ec->iconic || e_client_util_ignored_get(ec)) return;
3147 if ((ec->mouse.current.mx == output->x) && (ec->mouse.current.my == output->y)) return;
3148 ec->mouse.current.mx = output->x;
3149 ec->mouse.current.my = output->y;
3150 if (ec->moving)
3151 {
3152 int x, y, new_x, new_y;
3153 int new_w, new_h;
3154 Eina_List *skiplist = NULL;
3155
3156 if (action_handler_key) return;
3157 if ((ec->moveinfo.down.button >= 1) && (ec->moveinfo.down.button <= 3))
3158 {
3159 x = ec->mouse.last_down[ec->moveinfo.down.button - 1].x +
3160 (ec->mouse.current.mx - ec->moveinfo.down.mx);
3161 y = ec->mouse.last_down[ec->moveinfo.down.button - 1].y +
3162 (ec->mouse.current.my - ec->moveinfo.down.my);
3163 }
3164 else
3165 {
3166 x = ec->moveinfo.down.x +
3167 (ec->mouse.current.mx - ec->moveinfo.down.mx);
3168 y = ec->moveinfo.down.y +
3169 (ec->mouse.current.my - ec->moveinfo.down.my);
3170 }
3171 e_comp_object_frame_xy_adjust(ec->frame, x, y, &new_x, &new_y);
3172
3173 skiplist = eina_list_append(skiplist, ec);
3174 e_resist_client_position(skiplist,
3175 ec->x, ec->y, ec->w, ec->h,
3176 x, y, ec->w, ec->h,
3177 &new_x, &new_y, &new_w, &new_h);
3178 eina_list_free(skiplist);
3179
3180 if (e_config->screen_limits == E_CLIENT_OFFSCREEN_LIMIT_ALLOW_NONE)
3181 _e_client_stay_within_canvas(ec, x, y, &new_x, &new_y);
3182
3183 ec->shelf_fix.x = 0;
3184 ec->shelf_fix.y = 0;
3185 ec->shelf_fix.modified = 0;
3186 evas_object_move(ec->frame, new_x, new_y);
3187 }
3188 else if (e_client_util_resizing_get(ec))
3189 {
3190 if (action_handler_key) return;
3191 _e_client_resize_handle(ec);
3192 }
3193 else if (ec->drag.start)
3194 {
3195 if ((ec->drag.x == -1) && (ec->drag.y == -1))
3196 {
3197 ec->drag.x = output->x;
3198 ec->drag.y = output->y;
3199 }
3200 else if (ec->zone)
3201 {
3202 int dx, dy;
3203
3204 dx = ec->drag.x - output->x;
3205 dy = ec->drag.y - output->y;
3206 if (((dx * dx) + (dy * dy)) >
3207 (e_config->drag_resist * e_config->drag_resist))
3208 {
3209 /* start drag! */
3210 if (
3211 #ifndef HAVE_WAYLAND_ONLY
3212 ec->netwm.icons ||
3213 #endif
3214 ec->desktop || ec->internal_icon)
3215 {
3216 Evas_Object *o = NULL;
3217 int x, y, w, h;
3218 const char *drag_types[] = { "enlightenment/border" };
3219
3220 REFD(ec, 1);
3221 e_object_ref(E_OBJECT(ec));
3222 e_comp_object_frame_icon_geometry_get(ec->frame, &x, &y, &w, &h);
3223
3224 client_drag = e_drag_new(output->x, output->y,
3225 drag_types, 1, ec, -1,
3226 NULL,
3227 _e_client_cb_drag_finished);
3228 client_drag->button_mask = evas_pointer_button_down_mask_get(e_comp->evas);
3229 e_drag_resize(client_drag, w, h);
3230
3231 o = e_client_icon_add(ec, client_drag->evas);
3232 if (!o)
3233 {
3234 /* FIXME: fallback icon for drag */
3235 o = evas_object_rectangle_add(client_drag->evas);
3236 evas_object_color_set(o, 255, 255, 255, 255);
3237 }
3238
3239 e_drag_object_set(client_drag, o);
3240 e_drag_start(client_drag,
3241 output->x + (ec->drag.x - x),
3242 output->y + (ec->drag.y - y));
3243 }
3244 ec->drag.start = 0;
3245 }
3246 }
3247 }
3248 }
3249 ///////////////////////////////////////////////////////
3250
3251 E_API void
e_client_res_change_geometry_save(E_Client * ec)3252 e_client_res_change_geometry_save(E_Client *ec)
3253 {
3254 E_OBJECT_CHECK(ec);
3255 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
3256
3257 if (ec->pre_res_change.valid) return;
3258 ec->pre_res_change.valid = 1;
3259 ec->pre_res_change.x = ec->x;
3260 ec->pre_res_change.y = ec->y;
3261 ec->pre_res_change.w = ec->w;
3262 ec->pre_res_change.h = ec->h;
3263 ec->pre_res_change.saved.x = ec->saved.x;
3264 ec->pre_res_change.saved.y = ec->saved.y;
3265 ec->pre_res_change.saved.w = ec->saved.w;
3266 ec->pre_res_change.saved.h = ec->saved.h;
3267 }
3268
3269 E_API void
e_client_res_change_geometry_restore(E_Client * ec)3270 e_client_res_change_geometry_restore(E_Client *ec)
3271 {
3272 struct
3273 {
3274 unsigned char valid E_BITFIELD;
3275 int x, y, w, h;
3276 struct
3277 {
3278 int x, y, w, h;
3279 } saved;
3280 } pre_res_change;
3281
3282 E_OBJECT_CHECK(ec);
3283 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
3284 if (!ec->pre_res_change.valid) return;
3285 if (ec->new_client) return;
3286 if (!ec->zone) return;
3287
3288 memcpy(&pre_res_change, &ec->pre_res_change, sizeof(pre_res_change));
3289
3290 if (ec->fullscreen)
3291 {
3292 if ((eina_list_count(e_comp->zones) > 1) ||
3293 (e_config->fullscreen_policy == E_FULLSCREEN_RESIZE))
3294 evas_object_geometry_set(ec->frame, ec->zone->x, ec->zone->y, ec->zone->w, ec->zone->h);
3295 else
3296 {
3297 e_client_unfullscreen(ec);
3298 e_client_fullscreen(ec, e_config->fullscreen_policy);
3299 }
3300 }
3301 else if (ec->maximized != E_MAXIMIZE_NONE)
3302 {
3303 int x, y, w, h;
3304
3305 if (e_client_maximize_geometry_get(ec, ec->maximized, &x, &y, &w, &h))
3306 {
3307 Eina_Bool override = ec->maximize_override;
3308 ec->maximize_override = 1;
3309 evas_object_geometry_set(ec->frame, x, y, w, h);
3310 ec->maximize_override = override;
3311 }
3312 else
3313 {
3314 E_Maximize max = ec->maximized;
3315 e_client_unmaximize(ec, E_MAXIMIZE_BOTH);
3316 e_client_maximize(ec, max);
3317 }
3318 }
3319 else
3320 {
3321 int x, y, w, h, zx, zy, zw, zh;
3322
3323 ec->saved.x = ec->pre_res_change.saved.x;
3324 ec->saved.y = ec->pre_res_change.saved.y;
3325 ec->saved.w = ec->pre_res_change.saved.w;
3326 ec->saved.h = ec->pre_res_change.saved.h;
3327
3328 e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh);
3329
3330 if (ec->saved.w > zw)
3331 ec->saved.w = zw;
3332 if ((ec->saved.x + ec->saved.w) > (zx + zw))
3333 ec->saved.x = zx + zw - ec->saved.w;
3334
3335 if (ec->saved.h > zh)
3336 ec->saved.h = zh;
3337 if ((ec->saved.y + ec->saved.h) > (zy + zh))
3338 ec->saved.y = zy + zh - ec->saved.h;
3339
3340 x = ec->pre_res_change.x;
3341 y = ec->pre_res_change.y;
3342 w = ec->pre_res_change.w;
3343 h = ec->pre_res_change.h;
3344 if (w > zw)
3345 w = zw;
3346 if (h > zh)
3347 h = zh;
3348 if ((x + w) > (zx + zw))
3349 x = zx + zw - w;
3350 if ((y + h) > (zy + zh))
3351 y = zy + zh - h;
3352 evas_object_move(ec->frame, x, y);
3353 if (w && h)
3354 {
3355 e_client_resize_limit(ec, &w, &h);
3356 evas_object_resize(ec->frame, w, h);
3357 }
3358 }
3359 memcpy(&ec->pre_res_change, &pre_res_change, sizeof(pre_res_change));
3360 }
3361
3362 E_API void
e_client_rescale(E_Client * ec)3363 e_client_rescale(E_Client *ec)
3364 {
3365 Eina_Bool shaded;
3366 int shade_dir;
3367
3368 if (stopping) return;
3369 E_OBJECT_CHECK(ec);
3370 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
3371
3372 if (e_comp->updating)
3373 {
3374 ec->changes.need_rescale = 1;
3375 EC_CHANGED(ec);
3376 return;
3377 }
3378 ec->changes.need_rescale = 0;
3379
3380 shaded = ec->shaded;
3381 shade_dir = ec->shade_dir;
3382 if (shaded) e_client_unshade(ec, shade_dir);
3383 ec->pre_res_change.valid = 0;
3384 e_client_res_change_geometry_save(ec);
3385 e_client_res_change_geometry_restore(ec);
3386 if (shaded) e_client_shade(ec, shade_dir);
3387 }
3388
3389 E_API void
e_client_zone_set(E_Client * ec,E_Zone * zone)3390 e_client_zone_set(E_Client *ec, E_Zone *zone)
3391 {
3392 E_Event_Client_Zone_Set *ev;
3393
3394 E_OBJECT_CHECK(ec);
3395 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
3396 E_OBJECT_CHECK(zone);
3397 E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
3398 if (ec->zone == zone) return;
3399
3400 /* if the window does not lie in the new zone, move it so that it does */
3401 if (!E_INTERSECTS(ec->x, ec->y, ec->w, ec->h, zone->x, zone->y, zone->w, zone->h))
3402 {
3403 int x, y;
3404
3405 if (ec->zone)
3406 {
3407 /* first guess -- get offset from old zone, and apply to new zone */
3408 x = zone->x + (ec->x - ec->zone->x);
3409 y = zone->y + (ec->y - ec->zone->y);
3410 }
3411 else
3412 x = ec->x, y = ec->y;
3413
3414 /* keep window from hanging off bottom and left */
3415 if (x + ec->w > zone->x + zone->w) x += (zone->x + zone->w) - (x + ec->w);
3416 if (y + ec->h > zone->y + zone->h) y += (zone->y + zone->h) - (y + ec->h);
3417
3418 /* make sure to and left are on screen (if the window is larger than the zone, it will hang off the bottom / right) */
3419 if (x < zone->x) x = zone->x;
3420 if (y < zone->y) y = zone->y;
3421
3422 if (!E_INTERSECTS(x, y, ec->w, ec->h, zone->x, zone->y, zone->w, zone->h))
3423 {
3424 /* still not in zone at all, so just move it to closest edge */
3425 if (x < zone->x) x = zone->x;
3426 if (x >= zone->x + zone->w) x = zone->x + zone->w - ec->w;
3427 if (y < zone->y) y = zone->y;
3428 if (y >= zone->y + zone->h) y = zone->y + zone->h - ec->h;
3429 }
3430 evas_object_move(ec->frame, x, y);
3431 }
3432
3433 ec->zone = zone;
3434
3435 if ((!ec->desk) || (ec->desk->zone != ec->zone))
3436 e_client_desk_set(ec, e_desk_current_get(ec->zone));
3437
3438 ev = E_NEW(E_Event_Client_Zone_Set, 1);
3439 ev->ec = ec;
3440 REFD(ec, 5);
3441 e_object_ref(E_OBJECT(ec));
3442 ev->zone = zone;
3443 e_object_ref(E_OBJECT(zone));
3444
3445 ecore_event_add(E_EVENT_CLIENT_ZONE_SET, ev, (Ecore_End_Cb)_e_client_event_zone_set_free, NULL);
3446
3447 e_remember_update(ec);
3448 if (ec->maximized || ec->fullscreen)
3449 e_client_rescale(ec);
3450 }
3451
3452 E_API void
e_client_geometry_get(E_Client * ec,int * x,int * y,int * w,int * h)3453 e_client_geometry_get(E_Client *ec, int *x, int *y, int *w, int *h)
3454 {
3455 E_OBJECT_CHECK(ec);
3456 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
3457
3458 if (ec->frame)
3459 evas_object_geometry_get(ec->frame, x, y, w, h);
3460 else
3461 {
3462 if (x) *x = ec->x;
3463 if (y) *y = ec->y;
3464 if (w) *w = ec->w;
3465 if (h) *h = ec->h;
3466 }
3467 }
3468
3469 E_API E_Client *
e_client_above_get(const E_Client * ec)3470 e_client_above_get(const E_Client *ec)
3471 {
3472 unsigned int x;
3473 E_Client *ec2;
3474
3475 EINA_SAFETY_ON_NULL_RETURN_VAL(ec, NULL);
3476 if (EINA_INLIST_GET(ec)->next) //check current layer
3477 {
3478 EINA_INLIST_FOREACH(EINA_INLIST_GET(ec)->next, ec2)
3479 if (!e_object_is_del(E_OBJECT(ec2)))
3480 return ec2;
3481 }
3482 if (ec->layer == E_LAYER_CLIENT_PRIO) return NULL;
3483 if (e_comp_canvas_client_layer_map(ec->layer) == 9999) return NULL;
3484
3485 /* go up the layers until we find one */
3486 for (x = e_comp_canvas_layer_map(ec->layer) + 1; x <= e_comp_canvas_layer_map(E_LAYER_CLIENT_PRIO); x++)
3487 {
3488 if (!e_comp->layers[x].clients) continue;
3489 EINA_INLIST_FOREACH(e_comp->layers[x].clients, ec2)
3490 if (!e_object_is_del(E_OBJECT(ec2)))
3491 return ec2;
3492 }
3493 return NULL;
3494 }
3495
3496 E_API E_Client *
e_client_below_get(const E_Client * ec)3497 e_client_below_get(const E_Client *ec)
3498 {
3499 unsigned int x;
3500 E_Client *ec2;
3501 Eina_Inlist *l;
3502
3503 E_OBJECT_CHECK_RETURN(ec, NULL);
3504 E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, NULL);
3505
3506 EINA_SAFETY_ON_NULL_RETURN_VAL(ec, NULL);
3507 if (EINA_INLIST_GET(ec)->prev) //check current layer
3508 {
3509 for (l = EINA_INLIST_GET(ec)->prev; l; l = l->prev)
3510 {
3511 ec2 = EINA_INLIST_CONTAINER_GET(l, E_Client);;
3512 if (!e_object_is_del(E_OBJECT(ec2)))
3513 return ec2;
3514 }
3515 }
3516 if (ec->layer == E_LAYER_CLIENT_DESKTOP) return NULL;
3517 if (e_comp_canvas_client_layer_map(ec->layer) == 9999) return NULL;
3518
3519 /* go down the layers until we find one */
3520 x = e_comp_canvas_layer_map(ec->layer);
3521 if (x > 0) x--;
3522
3523 for (; x >= e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP); x--)
3524 {
3525 if (!e_comp->layers[x].clients) continue;
3526 EINA_INLIST_REVERSE_FOREACH(e_comp->layers[x].clients, ec2)
3527 if (!e_object_is_del(E_OBJECT(ec2)))
3528 return ec2;
3529 }
3530 return NULL;
3531 }
3532
3533 E_API E_Client *
e_client_bottom_get(void)3534 e_client_bottom_get(void)
3535 {
3536 unsigned int x;
3537
3538 for (x = e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP); x <= e_comp_canvas_layer_map(E_LAYER_CLIENT_PRIO); x++)
3539 {
3540 E_Client *ec2;
3541
3542 if (!e_comp->layers[x].clients) continue;
3543 EINA_INLIST_FOREACH(e_comp->layers[x].clients, ec2)
3544 if (!e_object_is_del(E_OBJECT(ec2)))
3545 return ec2;
3546 }
3547 return NULL;
3548 }
3549
3550 E_API E_Client *
e_client_top_get(void)3551 e_client_top_get(void)
3552 {
3553 unsigned int x;
3554
3555 for (x = e_comp_canvas_layer_map(E_LAYER_CLIENT_PRIO); x >= e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP); x--)
3556 {
3557 E_Client *ec2;
3558
3559 if (!e_comp->layers[x].clients) continue;
3560 EINA_INLIST_REVERSE_FOREACH(e_comp->layers[x].clients, ec2)
3561 if (!e_object_is_del(E_OBJECT(ec2)))
3562 return ec2;
3563 }
3564 return NULL;
3565 }
3566
3567 E_API unsigned int
e_clients_count(void)3568 e_clients_count(void)
3569 {
3570 return eina_list_count(e_comp->clients);
3571 }
3572
3573
3574 /**
3575 * Set a callback which will be called just prior to updating the
3576 * move coordinates for a border
3577 */
3578 E_API void
e_client_move_intercept_cb_set(E_Client * ec,E_Client_Move_Intercept_Cb cb)3579 e_client_move_intercept_cb_set(E_Client *ec, E_Client_Move_Intercept_Cb cb)
3580 {
3581 ec->move_intercept_cb = cb;
3582 }
3583
3584 ///////////////////////////////////////
3585
3586 E_API E_Client_Hook *
e_client_hook_add(E_Client_Hook_Point hookpoint,E_Client_Hook_Cb func,const void * data)3587 e_client_hook_add(E_Client_Hook_Point hookpoint, E_Client_Hook_Cb func, const void *data)
3588 {
3589 E_Client_Hook *ch;
3590
3591 EINA_SAFETY_ON_TRUE_RETURN_VAL(hookpoint >= E_CLIENT_HOOK_LAST, NULL);
3592 ch = E_NEW(E_Client_Hook, 1);
3593 if (!ch) return NULL;
3594 ch->hookpoint = hookpoint;
3595 ch->func = func;
3596 ch->data = (void*)data;
3597 _e_client_hooks[hookpoint] = eina_inlist_append(_e_client_hooks[hookpoint], EINA_INLIST_GET(ch));
3598 return ch;
3599 }
3600
3601 E_API void
e_client_hook_del(E_Client_Hook * ch)3602 e_client_hook_del(E_Client_Hook *ch)
3603 {
3604 ch->delete_me = 1;
3605 if (_e_client_hooks_walking == 0)
3606 {
3607 _e_client_hooks[ch->hookpoint] = eina_inlist_remove(_e_client_hooks[ch->hookpoint], EINA_INLIST_GET(ch));
3608 free(ch);
3609 }
3610 else
3611 _e_client_hooks_delete++;
3612 }
3613
3614 ///////////////////////////////////////
3615
3616 E_API void
e_client_focus_latest_set(E_Client * ec)3617 e_client_focus_latest_set(E_Client *ec)
3618 {
3619 if (!ec) CRI("ACK");
3620 if (focus_track_frozen > 0) return;
3621 focus_stack = eina_list_remove(focus_stack, ec);
3622 focus_stack = eina_list_prepend(focus_stack, ec);
3623 }
3624
3625 E_API void
e_client_raise_latest_set(E_Client * ec)3626 e_client_raise_latest_set(E_Client *ec)
3627 {
3628 if (!ec) CRI("ACK");
3629 raise_stack = eina_list_remove(raise_stack, ec);
3630 raise_stack = eina_list_prepend(raise_stack, ec);
3631 }
3632
3633 E_API Eina_Bool
e_client_focus_track_enabled(void)3634 e_client_focus_track_enabled(void)
3635 {
3636 return !focus_track_frozen;
3637 }
3638
3639 E_API void
e_client_focus_track_freeze(void)3640 e_client_focus_track_freeze(void)
3641 {
3642 focus_track_frozen++;
3643 }
3644
3645 E_API void
e_client_focus_track_thaw(void)3646 e_client_focus_track_thaw(void)
3647 {
3648 if (focus_track_frozen)
3649 focus_track_frozen--;
3650 }
3651
3652 E_API void
e_client_refocus(void)3653 e_client_refocus(void)
3654 {
3655 E_Client *ec;
3656 const Eina_List *l;
3657
3658 EINA_LIST_FOREACH(e_client_focus_stack_get(), l, ec)
3659 if (ec->desk && ec->desk->visible && (!ec->iconic))
3660 {
3661 if (e_comp->input_key_grabs || e_comp->input_mouse_grabs) break;
3662 evas_object_focus_set(ec->frame, 1);
3663 break;
3664 }
3665 }
3666
3667
3668 /*
3669 * Sets the focus to the given client if necessary
3670 * There are 3 cases of different focus_policy-configurations:
3671 *
3672 * - E_FOCUS_CLICK: just set the focus, the most simple one
3673 *
3674 * - E_FOCUS_MOUSE: focus is where the mouse is, so try to
3675 * warp the pointer to the window. If this fails (because
3676 * the pointer is already in the window), just set the focus.
3677 *
3678 * - E_FOCUS_SLOPPY: focus is where the mouse is or on the
3679 * last window which was focused, if the mouse is on the
3680 * desktop. So, we need to look if there is another window
3681 * under the pointer and warp to pointer to the right
3682 * one if so (also, we set the focus afterwards). In case
3683 * there is no window under pointer, the pointer is on the
3684 * desktop and so we just set the focus.
3685 *
3686 *
3687 * This function is to be called when setting the focus was not
3688 * explicitly triggered by the user (by moving the mouse or
3689 * clicking for example), but implicitly (by closing a window,
3690 * the last focused window should get focus).
3691 *
3692 */
3693 E_API void
e_client_focus_set_with_pointer(E_Client * ec)3694 e_client_focus_set_with_pointer(E_Client *ec)
3695 {
3696 E_OBJECT_CHECK(ec);
3697 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
3698 /* note: this is here as it seems there are enough apps that do not even
3699 * expect us to emulate a look of focus but not actually set x input
3700 * focus as we do - so simply abort any focuse set on such windows */
3701 if (e_pixmap_is_x(ec->pixmap))
3702 {
3703 /* be strict about accepting focus hint */
3704 if ((!ec->icccm.accepts_focus) &&
3705 (!ec->icccm.take_focus)) return;
3706 }
3707 ec = e_client_stack_active_adjust(ec);
3708 if (ec->lock_focus_out) return;
3709 if (ec == focused) return;
3710 evas_object_focus_set(ec->frame, 1);
3711
3712 if (e_config->focus_policy == E_FOCUS_CLICK) return;
3713 if (!ec->visible) return;
3714
3715 if (e_config->focus_policy == E_FOCUS_SLOPPY)
3716 {
3717 E_Client *pec;
3718 pec = e_client_under_pointer_get(ec->desk, ec);
3719 /* Do not slide pointer when disabled (probably breaks focus
3720 * on sloppy/mouse focus but requested by users). */
3721 if (e_config->pointer_slide && pec && (pec != ec))
3722 e_client_pointer_warp_to_center(ec);
3723 }
3724 else
3725 {
3726 if (e_config->pointer_slide)
3727 e_client_pointer_warp_to_center(ec);
3728 }
3729 }
3730
3731 static Eina_Bool
_e_client_is_in_parents(E_Client * ec,E_Client * ec_find)3732 _e_client_is_in_parents(E_Client *ec, E_Client *ec_find)
3733 {
3734 if (ec == ec_find) return EINA_TRUE;
3735 if (e_object_is_del(E_OBJECT(ec))) return EINA_FALSE;
3736 if (ec->parent) return _e_client_is_in_parents(ec->parent, ec_find);
3737 return EINA_FALSE;
3738 }
3739
3740 EINTERN void
e_client_focused_set(E_Client * ec)3741 e_client_focused_set(E_Client *ec)
3742 {
3743 E_Client *ec2, *ec_unfocus = focused;
3744 Eina_List *l, *ll;
3745
3746 if (ec == focused) return;
3747 focused = ec;
3748 if ((ec) && (ec->zone))
3749 {
3750 ec->focused = 1;
3751 e_client_urgent_set(ec, 0);
3752 if (!e_config->allow_above_fullscreen)
3753 {
3754 int x, total = ec->zone->desk_x_count * ec->zone->desk_y_count;
3755
3756 for (x = 0; x < total; x++)
3757 {
3758 E_Desk *desk = ec->zone->desks[x];
3759 /* if there's any fullscreen non-parents on this desk, unfullscreen them */
3760 EINA_LIST_FOREACH_SAFE(desk->fullscreen_clients, l, ll, ec2)
3761 {
3762 if (ec2 == ec) continue;
3763 if (e_object_is_del(E_OBJECT(ec2))) continue;
3764 /* but only if it's the same desk or one of the clients is sticky */
3765 if ((desk == ec->desk) || (ec->sticky || ec2->sticky))
3766 {
3767 if (!_e_client_is_in_parents(ec, ec2))
3768 e_client_unfullscreen(ec2);
3769 }
3770 }
3771 }
3772 }
3773 }
3774
3775 while ((ec_unfocus) && (ec_unfocus->zone))
3776 {
3777 Eina_Bool is_popup, is_child;
3778
3779 ec_unfocus->want_focus = ec_unfocus->focused = 0;
3780 if (!e_object_is_del(E_OBJECT(ec_unfocus)))
3781 e_focus_event_focus_out(ec_unfocus);
3782 if (ec_unfocus->mouse.in && ec && (!e_client_util_is_popup(ec)) &&
3783 (e_config->focus_policy != E_FOCUS_CLICK) && e_config->pointer_slide)
3784 e_client_mouse_out(ec_unfocus, ec_unfocus->x - 1, ec_unfocus->y - 1);
3785
3786 E_FREE_FUNC(ec_unfocus->raise_timer, ecore_timer_del);
3787
3788 is_popup = EINA_FALSE;
3789 is_child = EINA_FALSE;
3790 if ((ec) &&
3791 ((ec->netwm.type == E_WINDOW_TYPE_MENU) ||
3792 (ec->netwm.type == E_WINDOW_TYPE_TOOLBAR) ||
3793 (ec->netwm.type == E_WINDOW_TYPE_DOCK) ||
3794 (ec->netwm.type == E_WINDOW_TYPE_SPLASH) ||
3795 (ec->netwm.type == E_WINDOW_TYPE_TOOLTIP) ||
3796 (ec->netwm.type == E_WINDOW_TYPE_DROPDOWN_MENU) ||
3797 (ec->netwm.type == E_WINDOW_TYPE_POPUP_MENU) ||
3798 (ec->netwm.type == E_WINDOW_TYPE_COMBO) ||
3799 (ec->netwm.type == E_WINDOW_TYPE_DND) ||
3800 (ec->netwm.type == E_WINDOW_TYPE_NOTIFICATION)))
3801 is_popup = EINA_TRUE;
3802 if ((ec) && _e_client_is_in_parents(ec, ec_unfocus))
3803 is_child = EINA_TRUE;
3804
3805 /* if there unfocus client is fullscreen and visible */
3806 if ((!is_popup) && (!is_child) &&
3807 (!e_config->allow_above_fullscreen) &&
3808 (ec_unfocus->fullscreen) && (!ec_unfocus->iconic) && (!ec_unfocus->hidden) &&
3809 (ec_unfocus->zone == e_zone_current_get()) &&
3810 ((ec_unfocus->desk == e_desk_current_get(ec_unfocus->zone)) || (ec_unfocus->sticky)))
3811 {
3812 Eina_Bool have_vis_child = EINA_FALSE;
3813
3814 /* if any of its children are visible */
3815 EINA_LIST_FOREACH(ec_unfocus->transients, l, ec2)
3816 {
3817 if ((ec2->zone == ec_unfocus->zone) &&
3818 ((ec2->desk == ec_unfocus->desk) ||
3819 (ec2->sticky) || (ec_unfocus->sticky)))
3820 {
3821 have_vis_child = EINA_TRUE;
3822 break;
3823 }
3824 }
3825 /* if no children are visible, unfullscreen */
3826 if ((!e_object_is_del(E_OBJECT(ec_unfocus))) && (!have_vis_child))
3827 e_client_unfullscreen(ec_unfocus);
3828 }
3829
3830 _e_client_hook_call(E_CLIENT_HOOK_FOCUS_UNSET, ec_unfocus);
3831 /* only send event here if we're not being deleted */
3832 if ((!e_object_is_del(E_OBJECT(ec_unfocus))) &&
3833 (e_object_ref_get(E_OBJECT(ec_unfocus)) > 0))
3834 {
3835 _e_client_event_simple(ec_unfocus, E_EVENT_CLIENT_FOCUS_OUT);
3836 e_client_urgent_set(ec_unfocus, ec_unfocus->icccm.urgent);
3837 }
3838 break;
3839 }
3840 if (!ec) return;
3841
3842 _e_client_hook_call(E_CLIENT_HOOK_FOCUS_SET, ec);
3843 e_focus_event_focus_in(ec);
3844
3845 if (!focus_track_frozen)
3846 e_client_focus_latest_set(ec);
3847
3848 e_hints_active_window_set(ec);
3849 _e_client_event_simple(ec, E_EVENT_CLIENT_FOCUS_IN);
3850 if (ec->sticky && ec->desk && (!ec->desk->visible))
3851 e_client_desk_set(ec, e_desk_current_get(ec->zone));
3852 }
3853
3854 E_API void
e_client_activate(E_Client * ec,Eina_Bool just_do_it)3855 e_client_activate(E_Client *ec, Eina_Bool just_do_it)
3856 {
3857 E_OBJECT_CHECK(ec);
3858 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
3859 ec = e_client_stack_active_adjust(ec);
3860 if ((e_config->focus_setting == E_FOCUS_NEW_WINDOW) ||
3861 ((ec->parent) &&
3862 ((e_config->focus_setting == E_FOCUS_NEW_DIALOG) ||
3863 ((ec->parent->focused) &&
3864 (e_config->focus_setting == E_FOCUS_NEW_DIALOG_IF_OWNER_FOCUSED)))) ||
3865 (just_do_it))
3866 {
3867 if (ec->iconic)
3868 {
3869 if (e_config->clientlist_warp_to_iconified_desktop == 1)
3870 e_desk_show(ec->desk);
3871
3872 if (!ec->lock_user_iconify)
3873 e_client_uniconify(ec);
3874 }
3875 if ((!ec->iconic) && ((!ec->sticky) || e_config->focus_revert_allow_sticky))
3876 {
3877 int val = e_config->focus_last_focused_per_desktop;
3878
3879 /* prevent infinite focus loops during refocus */
3880 if (!ec->lock_focus_out)
3881 e_config->focus_last_focused_per_desktop = 0;
3882 e_desk_show(ec->desk);
3883 e_config->focus_last_focused_per_desktop = val;
3884 }
3885 if (!ec->lock_user_stacking)
3886 evas_object_raise(ec->frame);
3887 if (ec->shaded || ec->shading)
3888 e_client_unshade(ec, ec->shade_dir);
3889 if (!ec->lock_focus_out)
3890 {
3891 /* XXX ooffice does send this request for
3892 config dialogs when the main window gets focus.
3893 causing the pointer to jump back and forth. */
3894 if ((e_config->focus_policy != E_FOCUS_CLICK) && (!ec->new_client) &&
3895 (!e_config->disable_all_pointer_warps) &&
3896 (!e_util_strcmp(ec->icccm.name, "VCLSalFrame")))
3897 ecore_evas_pointer_warp(e_comp->ee,
3898 ec->x + (ec->w / 2), ec->y + (ec->h / 2));
3899 evas_object_focus_set(ec->frame, 1);
3900 }
3901 }
3902 }
3903
3904 E_API E_Client *
e_client_focused_get(void)3905 e_client_focused_get(void)
3906 {
3907 return focused;
3908 }
3909
3910 E_API Eina_List *
e_client_focus_stack_get(void)3911 e_client_focus_stack_get(void)
3912 {
3913 return focus_stack;
3914 }
3915
3916 YOLO E_API void
e_client_focus_stack_set(Eina_List * l)3917 e_client_focus_stack_set(Eina_List *l)
3918 {
3919 focus_stack = l;
3920 }
3921
3922 E_API Eina_List *
e_client_raise_stack_get(void)3923 e_client_raise_stack_get(void)
3924 {
3925 return raise_stack;
3926 }
3927
3928 E_API Eina_List *
e_client_lost_windows_get(E_Zone * zone)3929 e_client_lost_windows_get(E_Zone *zone)
3930 {
3931 Eina_List *list = NULL;
3932 const Eina_List *l;
3933 E_Client *ec;
3934 int loss_overlap = 5;
3935
3936 E_OBJECT_CHECK_RETURN(zone, NULL);
3937 E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, NULL);
3938 EINA_LIST_FOREACH(e_comp->clients, l, ec)
3939 {
3940 if (ec->zone != zone) continue;
3941 if (e_client_util_ignored_get(ec)) continue;
3942
3943 if (!E_INTERSECTS(ec->zone->x + loss_overlap,
3944 ec->zone->y + loss_overlap,
3945 ec->zone->w - (2 * loss_overlap),
3946 ec->zone->h - (2 * loss_overlap),
3947 ec->x, ec->y, ec->w, ec->h))
3948 {
3949 list = eina_list_append(list, ec);
3950 }
3951 }
3952 return list;
3953 }
3954
3955 ///////////////////////////////////////
3956
3957 E_API void
e_client_shade(E_Client * ec,E_Direction dir)3958 e_client_shade(E_Client *ec, E_Direction dir)
3959 {
3960 E_OBJECT_CHECK(ec);
3961 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
3962 if (((!ec->shaded) && ec->shading) || (ec->shaded && (!ec->shading)) || (ec->fullscreen) ||
3963 ((ec->maximized) && (!e_config->allow_manip))) return;
3964 if (!e_util_strcmp("borderless", ec->bordername)) return;
3965 if (!e_comp_object_frame_allowed(ec->frame)) return;
3966
3967 e_hints_window_shaded_set(ec, 1);
3968 e_hints_window_shade_direction_set(ec, dir);
3969 ec->take_focus = 0;
3970 ec->shading = 1;
3971 ec->shade_dir = dir;
3972
3973 if (e_config->border_shade_animate && (!ec->new_client))
3974 {
3975 ec->changes.shading = 1;
3976 EC_CHANGED(ec);
3977
3978 evas_object_smart_callback_call(ec->frame, "shading", (uintptr_t*)dir);
3979 }
3980 else
3981 evas_object_smart_callback_call(ec->frame, "shaded", (uintptr_t*)dir);
3982
3983 e_remember_update(ec);
3984 }
3985
3986 E_API void
e_client_unshade(E_Client * ec,E_Direction dir)3987 e_client_unshade(E_Client *ec, E_Direction dir)
3988 {
3989 E_OBJECT_CHECK(ec);
3990 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
3991 if ((!ec->shaded) || (ec->shading))
3992 return;
3993
3994 e_hints_window_shaded_set(ec, 0);
3995 e_hints_window_shade_direction_set(ec, dir);
3996 ec->shading = 1;
3997 ec->shade_dir = 0;
3998
3999 if (e_config->border_shade_animate)
4000 {
4001 ec->changes.shading = 1;
4002 EC_CHANGED(ec);
4003
4004 evas_object_smart_callback_call(ec->frame, "unshading", (uintptr_t*)dir);
4005 }
4006 else
4007 evas_object_smart_callback_call(ec->frame, "unshaded", (uintptr_t*)dir);
4008
4009 e_remember_update(ec);
4010 }
4011
4012 ///////////////////////////////////////
4013
4014 E_API Eina_Bool
e_client_maximize_geometry_get(const E_Client * ec,E_Maximize max,int * mx,int * my,int * mw,int * mh)4015 e_client_maximize_geometry_get(const E_Client *ec, E_Maximize max, int *mx, int *my, int *mw, int *mh)
4016 {
4017 int x1, yy1, x2, y2;
4018 int x = 0, y = 0, w, h, pw, ph;
4019 int zx, zy, zw, zh;
4020 int ecx, ecy, ecw, ech;
4021
4022 if (e_client_util_ignored_get(ec)) return EINA_FALSE;
4023 zx = zy = zw = zh = 0;
4024
4025 switch (max & E_MAXIMIZE_TYPE)
4026 {
4027 case E_MAXIMIZE_FULLSCREEN:
4028 w = ec->zone->w;
4029 h = ec->zone->h;
4030
4031 e_client_resize_limit(ec, &w, &h);
4032 /* center x-direction */
4033 x1 = ec->zone->x + (ec->zone->w - w) / 2;
4034 /* center y-direction */
4035 yy1 = ec->zone->y + (ec->zone->h - h) / 2;
4036
4037 switch (max & E_MAXIMIZE_DIRECTION)
4038 {
4039 case E_MAXIMIZE_BOTH:
4040 x = x1, y = yy1;
4041 break;
4042
4043 case E_MAXIMIZE_VERTICAL:
4044 x = ec->x, y = yy1, w = ec->w;
4045 break;
4046
4047 case E_MAXIMIZE_HORIZONTAL:
4048 x = x1, y = ec->y, h = ec->h;
4049 break;
4050
4051 case E_MAXIMIZE_LEFT:
4052 x = ec->zone->x, y = ec->zone->y, w /= 2;
4053 break;
4054
4055 case E_MAXIMIZE_RIGHT:
4056 x = x1, y = ec->zone->y, w /= 2;
4057 break;
4058 }
4059 if (mx) *mx = x;
4060 if (my) *my = y;
4061 if (mw) *mw = w;
4062 if (mh) *mh = h;
4063 break;
4064
4065 case E_MAXIMIZE_SMART:
4066 case E_MAXIMIZE_EXPAND:
4067 e_zone_desk_useful_geometry_get(ec->zone, ec->desk, &zx, &zy, &zw, &zh);
4068 w = zw, h = zh;
4069
4070 e_comp_object_frame_xy_unadjust(ec->frame, ec->x, ec->y, &ecx, &ecy);
4071 e_comp_object_frame_wh_unadjust(ec->frame, ec->w, ec->h, &ecw, &ech);
4072
4073 if (ecw < zw)
4074 w = ecw;
4075
4076 if (ech < zh)
4077 h = ech;
4078
4079 if (ecx < zx) // window left not useful coordinates
4080 x1 = zx;
4081 else if (ecx + ecw > zx + zw) // window right not useful coordinates
4082 x1 = zx + zw - ecw;
4083 else // window normal position
4084 x1 = ecx;
4085
4086 if (ecy < zy) // window top not useful coordinates
4087 yy1 = zy;
4088 else if (ecy + ech > zy + zh) // window bottom not useful coordinates
4089 yy1 = zy + zh - ech;
4090 else // window normal position
4091 yy1 = ecy;
4092
4093 switch (max & E_MAXIMIZE_DIRECTION)
4094 {
4095 case E_MAXIMIZE_BOTH:
4096 x = zx, y = zy, w = zw, h = zh;
4097 break;
4098
4099 case E_MAXIMIZE_VERTICAL:
4100 x = ec->x, y = zy, w = ec->w, h = zh;
4101 break;
4102
4103 case E_MAXIMIZE_HORIZONTAL:
4104 x = zx, y = ec->y, w = zw, h = ec->h;
4105 break;
4106
4107 case E_MAXIMIZE_LEFT:
4108 x = zx, y = zy, w = zw / 2, h = zh;
4109 break;
4110
4111 case E_MAXIMIZE_RIGHT:
4112 x = zx + zw / 2, y = zy, w = zw / 2, h = zh;
4113 break;
4114 }
4115 break;
4116
4117 case E_MAXIMIZE_FILL:
4118 x1 = ec->zone->x;
4119 yy1 = ec->zone->y;
4120 x2 = ec->zone->x + ec->zone->w;
4121 y2 = ec->zone->y + ec->zone->h;
4122
4123 e_zone_desk_useful_geometry_get(ec->zone, ec->desk, &zx, &zy, &zw, &zh);
4124 x1 = zx, yy1 = zy, x2 = x1 + zw, y2 = yy1 + zh;
4125
4126 w = x2 - x1;
4127 h = y2 - yy1;
4128 pw = w;
4129 ph = h;
4130 e_client_resize_limit(ec, &w, &h);
4131 /* center x-direction */
4132 x1 = x1 + (pw - w) / 2;
4133 /* center y-direction */
4134 yy1 = yy1 + (ph - h) / 2;
4135
4136 switch (max & E_MAXIMIZE_DIRECTION)
4137 {
4138 case E_MAXIMIZE_BOTH:
4139 x = x1, y = yy1;
4140 break;
4141
4142 case E_MAXIMIZE_VERTICAL:
4143 x = ec->x, y = yy1, w = ec->w;
4144 break;
4145
4146 case E_MAXIMIZE_HORIZONTAL:
4147 x = x1, y = ec->y, h = ec->h;
4148 break;
4149
4150 case E_MAXIMIZE_LEFT:
4151 x = ec->zone->x, y = ec->zone->y, w /= 2;
4152 break;
4153
4154 case E_MAXIMIZE_RIGHT:
4155 x = x1, y = ec->zone->y, w /= 2;
4156 break;
4157 }
4158 break;
4159 default:
4160 return EINA_FALSE;
4161 }
4162 if (mx) *mx = x;
4163 if (my) *my = y;
4164 if (mw) *mw = w;
4165 if (mh) *mh = h;
4166 return EINA_TRUE;
4167 }
4168
4169 E_API void
e_client_maximize(E_Client * ec,E_Maximize max)4170 e_client_maximize(E_Client *ec, E_Maximize max)
4171 {
4172 Eina_Bool override;
4173 E_OBJECT_CHECK(ec);
4174 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4175
4176 if (!ec->zone) return;
4177 if (ec->maximized == max) return;
4178 if (!(max & E_MAXIMIZE_DIRECTION)) max |= E_MAXIMIZE_BOTH;
4179
4180 if ((ec->shaded) || (ec->shading)) return;
4181
4182 /* Only allow changes in vertical/ horizontal maximization */
4183 if (((ec->maximized & E_MAXIMIZE_DIRECTION) == (max & E_MAXIMIZE_DIRECTION)) ||
4184 ((ec->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_BOTH)) return;
4185 if (ec->new_client)
4186 {
4187 ec->changes.need_maximize = 1;
4188 ec->maximized &= ~E_MAXIMIZE_TYPE;
4189 ec->maximized |= max;
4190 EC_CHANGED(ec);
4191 if (ec->re_manage) ec->changes.pos = 0;
4192 return;
4193 }
4194 if ((max & E_MAXIMIZE_TYPE) == E_MAXIMIZE_FULLSCREEN)
4195 evas_object_smart_callback_call(ec->frame, "fullscreen", NULL);
4196 else
4197 evas_object_smart_callback_call(ec->frame, "maximize", NULL);
4198 evas_object_smart_callback_call(ec->frame, "maximize_pre", &max);
4199 if (!max) return;
4200 if (ec->moving)
4201 {
4202 if (ec == action_client)
4203 e_comp_canvas_feed_mouse_up(0); //triggers event grabber cb
4204 }
4205 override = ec->maximize_override;
4206 if (ec->fullscreen)
4207 e_client_unfullscreen(ec);
4208 ec->pre_res_change.valid = 0;
4209 if (!ec->saved.set)
4210 {
4211 if (!(ec->maximized & E_MAXIMIZE_HORIZONTAL))
4212 {
4213 /* Horizontal hasn't been set */
4214 if (ec->changes.pos)
4215 e_comp_object_frame_xy_adjust(ec->frame, ec->x, 0, &ec->saved.x, NULL);
4216 else
4217 ec->saved.x = ec->client.x;
4218 ec->saved.x -= ec->zone->x;
4219 if (ec->visible)
4220 ec->saved.w = ec->client.w;
4221 }
4222 if (!(ec->maximized & E_MAXIMIZE_VERTICAL))
4223 {
4224 /* Vertical hasn't been set */
4225 if (ec->changes.pos)
4226 e_comp_object_frame_xy_adjust(ec->frame, 0, ec->y, NULL, &ec->saved.y);
4227 else
4228 ec->saved.y = ec->client.y;
4229 ec->saved.y -= ec->zone->y;
4230 if (ec->visible)
4231 ec->saved.h = ec->client.h;
4232 }
4233 ec->saved.zone = ec->zone->num;
4234 ec->saved.frame = e_comp_object_frame_exists(ec->frame) || (!e_comp_object_frame_allowed(ec->frame));
4235 }
4236
4237 ec->maximize_override = 1;
4238
4239 {
4240 int x, y, w, h;
4241 e_client_maximize_geometry_get(ec, max, &x, &y, &w, &h);
4242 if (!_e_client_maximize_run(ec, x, y, w, h))
4243 ec->maximize_override = override;
4244 }
4245
4246 /* Remove previous type */
4247 ec->maximized &= ~E_MAXIMIZE_TYPE;
4248 /* Add new maximization. It must be added, so that VERTICAL + HORIZONTAL == BOTH */
4249 ec->maximized |= max;
4250 ec->changes.need_unmaximize = 0;
4251
4252 if ((ec->maximized & E_MAXIMIZE_DIRECTION) > E_MAXIMIZE_BOTH)
4253 /* left/right maximize */
4254 e_hints_window_maximized_set(ec, 0,
4255 ((ec->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_LEFT) ||
4256 ((ec->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_RIGHT));
4257 else
4258 e_hints_window_maximized_set(ec, ec->maximized & E_MAXIMIZE_HORIZONTAL,
4259 ec->maximized & E_MAXIMIZE_VERTICAL);
4260 e_remember_update(ec);
4261 evas_object_smart_callback_call(ec->frame, "maximize_done", NULL);
4262 }
4263
4264 E_API Eina_Bool
e_client_unmaximize_geometry_get(const E_Client * ec,E_Maximize max,int * mx,int * my,int * mw,int * mh)4265 e_client_unmaximize_geometry_get(const E_Client *ec, E_Maximize max, int *mx, int *my, int *mw, int *mh)
4266 {
4267 int w, h, x, y;
4268
4269 if (e_client_util_ignored_get(ec)) return EINA_FALSE;
4270 if (!(ec->maximized & E_MAXIMIZE_TYPE)) return EINA_FALSE;
4271 if ((ec->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_FULLSCREEN)
4272 {
4273 if (mx) *mx = ec->saved.x + ec->zone->x;
4274 if (my) *my = ec->saved.y + ec->zone->y;
4275 if (mw) *mw = ec->saved.w;
4276 if (mh) *mh = ec->saved.h;
4277 return EINA_TRUE;
4278 }
4279
4280 w = ec->client.w;
4281 h = ec->client.h;
4282 x = ec->client.x;
4283 y = ec->client.y;
4284 max &= (ec->maximized & E_MAXIMIZE_DIRECTION);
4285
4286 if (max & E_MAXIMIZE_VERTICAL)
4287 {
4288 /* Remove vertical */
4289 h = ec->saved.h;
4290 y = ec->saved.y + ec->zone->y;
4291 }
4292 if (max & E_MAXIMIZE_HORIZONTAL)
4293 {
4294 /* Remove horizontal */
4295 w = ec->saved.w;
4296 x = ec->saved.x + ec->zone->x;
4297 }
4298 if (mx) *mx = x;
4299 if (my) *my = y;
4300 if (mw) *mw = w;
4301 if (mh) *mh = h;
4302 return EINA_TRUE;
4303 }
4304
4305 E_API void
e_client_unmaximize(E_Client * ec,E_Maximize max)4306 e_client_unmaximize(E_Client *ec, E_Maximize max)
4307 {
4308 E_Maximize unmax = max;
4309 E_OBJECT_CHECK(ec);
4310 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4311 if (!ec->zone) return;
4312 if (!(max & E_MAXIMIZE_DIRECTION))
4313 {
4314 CRI("BUG: Unmaximize call without direction!");
4315 return;
4316 }
4317 if (ec->new_client)
4318 {
4319 ec->changes.need_unmaximize = 1;
4320 EC_CHANGED(ec);
4321 return;
4322 }
4323
4324 if ((ec->shaded) || (ec->shading)) return;
4325
4326 /* Remove directions not used */
4327 unmax &= (ec->maximized & E_MAXIMIZE_DIRECTION);
4328 evas_object_smart_callback_call(ec->frame, "unmaximize_pre", &unmax);
4329 /* Can only remove existing maximization directions */
4330 if ((!unmax) && (!ec->need_fullscreen)) return;
4331 if (!unmax) unmax = max & (ec->maximized & E_MAXIMIZE_DIRECTION);
4332 if (ec->maximized & E_MAXIMIZE_TYPE)
4333 {
4334 ec->pre_res_change.valid = 0;
4335 ec->changes.need_maximize = 0;
4336
4337 if ((ec->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_FULLSCREEN)
4338 {
4339 E_Maximize tmp_max = ec->maximized;
4340
4341 //un-set maximized state for updating frame.
4342 ec->maximized = E_MAXIMIZE_NONE;
4343 _e_client_frame_update(ec);
4344 // re-set maximized state for unmaximize smart callback.
4345 ec->maximized = tmp_max;
4346 evas_object_smart_callback_call(ec->frame, "unfullscreen", NULL);
4347 // un-set maximized state.
4348 ec->maximized = E_MAXIMIZE_NONE;
4349 e_client_util_move_resize_without_frame(ec,
4350 ec->saved.x + ec->zone->x,
4351 ec->saved.y + ec->zone->y,
4352 ec->saved.w, ec->saved.h);
4353 ec->saved.x = ec->saved.y = ec->saved.w = ec->saved.h = 0;
4354 ec->saved.set = 0;
4355 e_hints_window_size_unset(ec);
4356 }
4357 else
4358 {
4359 int w, h, x, y;
4360 Eina_Bool horiz = EINA_FALSE, vert = EINA_FALSE;
4361 Eina_Bool fullscreen = !!eina_list_data_find(ec->desk->fullscreen_clients, ec);
4362
4363 e_client_unmaximize_geometry_get(ec, unmax, &x, &y, &w, &h);
4364 if (unmax & E_MAXIMIZE_VERTICAL)
4365 {
4366 /* Remove vertical */
4367 vert = EINA_TRUE;
4368 if ((unmax & E_MAXIMIZE_VERTICAL) == E_MAXIMIZE_VERTICAL)
4369 {
4370 if ((ec->maximized & E_MAXIMIZE_LEFT) == E_MAXIMIZE_LEFT)
4371 ec->maximized &= ~E_MAXIMIZE_LEFT;
4372 if ((ec->maximized & E_MAXIMIZE_RIGHT) == E_MAXIMIZE_RIGHT)
4373 ec->maximized &= ~E_MAXIMIZE_RIGHT;
4374 ec->maximized &= ~E_MAXIMIZE_VERTICAL;
4375 }
4376 if ((unmax & E_MAXIMIZE_LEFT) == E_MAXIMIZE_LEFT)
4377 ec->maximized &= ~E_MAXIMIZE_LEFT;
4378 if ((unmax & E_MAXIMIZE_RIGHT) == E_MAXIMIZE_RIGHT)
4379 ec->maximized &= ~E_MAXIMIZE_RIGHT;
4380 }
4381 if (unmax & E_MAXIMIZE_HORIZONTAL)
4382 {
4383 /* Remove horizontal */
4384 horiz = EINA_TRUE;
4385 ec->maximized &= ~E_MAXIMIZE_HORIZONTAL;
4386 }
4387
4388 if (!(ec->maximized & E_MAXIMIZE_DIRECTION))
4389 {
4390 ec->maximized = E_MAXIMIZE_NONE;
4391 _e_client_frame_update(ec);
4392 e_hints_window_size_unset(ec);
4393 }
4394 if (e_config->window_maximize_animate && (!ec->maximize_anims_disabled))
4395 ec->maximize_override = 1;
4396 if (!fullscreen)
4397 evas_object_smart_callback_call(ec->frame, "unmaximize", NULL);
4398 if (ec->saved.frame &&
4399 (e_comp_object_frame_exists(ec->frame) || (!e_comp_object_frame_allowed(ec->frame))))
4400 {
4401 e_comp_object_frame_xy_adjust(ec->frame, x, y, &x, &y);
4402 e_comp_object_frame_wh_adjust(ec->frame, w, h, &w, &h);
4403 }
4404 e_client_resize_limit(ec, &w, &h);
4405 if (fullscreen)
4406 evas_object_smart_callback_call(ec->frame, "unmaximize", NULL);
4407 if (!_e_client_maximize_run(ec, x, y, w, h))
4408 ec->maximize_override = 0;
4409 if (vert)
4410 ec->saved.h = ec->saved.y = 0;
4411 if (horiz)
4412 ec->saved.w = ec->saved.x = 0;
4413 if (vert && horiz)
4414 ec->saved.set = ec->saved.frame = 0;
4415 }
4416 e_hints_window_maximized_set(ec, ec->maximized & E_MAXIMIZE_HORIZONTAL,
4417 ec->maximized & E_MAXIMIZE_VERTICAL);
4418 }
4419 e_remember_update(ec);
4420 evas_object_smart_callback_call(ec->frame, "unmaximize_done", NULL);
4421 ec->changes.need_unmaximize = 0;
4422 }
4423
4424 E_API void
e_client_fullscreen(E_Client * ec,E_Fullscreen policy)4425 e_client_fullscreen(E_Client *ec, E_Fullscreen policy)
4426 {
4427 int x = 0, y = 0, w = 0, h = 0;
4428
4429 E_OBJECT_CHECK(ec);
4430 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4431 if (!ec->zone) return;
4432
4433 if ((ec->shaded) || (ec->shading) || ec->fullscreen) return;
4434 if ((!e_config->allow_above_fullscreen) && (!ec->desk->visible)) return;
4435 ec->need_fullscreen = 1;
4436 if (ec->new_client) return;
4437 if (e_comp->nocomp_ec && (ec->desk == e_comp->nocomp_ec->desk))
4438 {
4439 e_object_unref(E_OBJECT(e_comp->nocomp_ec));
4440 e_object_ref(E_OBJECT(ec));
4441 e_comp->nocomp_ec = ec;
4442 }
4443 ec->desk->fullscreen_clients = eina_list_append(ec->desk->fullscreen_clients, ec);
4444 ec->pre_res_change.valid = 0;
4445
4446 if (ec->maximized)
4447 {
4448 x = ec->saved.x;
4449 y = ec->saved.y;
4450 w = ec->saved.w;
4451 h = ec->saved.h;
4452 }
4453 else
4454 {
4455 if (ec->changes.pos)
4456 e_comp_object_frame_xy_adjust(ec->frame, ec->x, ec->y, &ec->saved.x, &ec->saved.y);
4457 else
4458 {
4459 ec->saved.x = ec->client.x;
4460 ec->saved.y = ec->client.y;
4461 }
4462 ec->saved.x -= ec->zone->x;
4463 ec->saved.y -= ec->zone->y;
4464
4465 if (ec->visible)
4466 {
4467 ec->saved.w = ec->client.w;
4468 ec->saved.h = ec->client.h;
4469 }
4470 }
4471 E_FREE_FUNC(ec->agent, evas_object_del);
4472 ec->saved.maximized = ec->maximized;
4473 ec->saved.zone = ec->zone->num;
4474 ec->saved.frame = e_comp_object_frame_exists(ec->frame) || (!e_comp_object_frame_allowed(ec->frame));
4475
4476 if (ec->maximized)
4477 {
4478 Eina_Bool maximize_anims_disabled = ec->maximize_anims_disabled;
4479
4480 ec->maximize_anims_disabled = 1;
4481 e_client_unmaximize(ec, E_MAXIMIZE_BOTH);
4482 ec->maximize_anims_disabled = maximize_anims_disabled;
4483 ec->saved.x = x;
4484 ec->saved.y = y;
4485 ec->saved.w = w;
4486 ec->saved.h = h;
4487 ec->saved.frame = e_comp_object_frame_exists(ec->frame) || (!e_comp_object_frame_allowed(ec->frame));
4488 }
4489
4490 ec->saved.layer = ec->layer;
4491 ec->saved.set = 1;
4492 if (!e_config->allow_above_fullscreen)
4493 evas_object_layer_set(ec->frame, E_LAYER_CLIENT_FULLSCREEN);
4494 else if (e_config->mode.presentation)
4495 evas_object_layer_set(ec->frame, E_LAYER_CLIENT_TOP);
4496
4497 ec->fullscreen = 1;
4498 #ifndef HAVE_WAYLAND_ONLY
4499 if ((eina_list_count(e_comp->zones) > 1) ||
4500 (policy == E_FULLSCREEN_RESIZE) || (!ecore_x_randr_query()))
4501 #else
4502 if ((eina_list_count(e_comp->zones) > 1) ||
4503 (policy == E_FULLSCREEN_RESIZE))
4504 #endif
4505 {
4506 evas_object_geometry_set(ec->frame, ec->zone->x, ec->zone->y, ec->zone->w, ec->zone->h);
4507 }
4508 else if (policy == E_FULLSCREEN_ZOOM)
4509 {
4510 /* compositor backends! */
4511 evas_object_smart_callback_call(ec->frame, "fullscreen_zoom", NULL);
4512 }
4513
4514 e_hints_window_fullscreen_set(ec, 1);
4515 e_hints_window_size_unset(ec);
4516 if (!e_client_util_ignored_get(ec))
4517 _e_client_frame_update(ec);
4518 ec->fullscreen_policy = policy;
4519 evas_object_smart_callback_call(ec->frame, "fullscreen", NULL);
4520
4521 _e_client_event_simple(ec, E_EVENT_CLIENT_FULLSCREEN);
4522
4523 e_remember_update(ec);
4524 ec->need_fullscreen = 0;
4525 }
4526
4527 E_API void
e_client_unfullscreen(E_Client * ec)4528 e_client_unfullscreen(E_Client *ec)
4529 {
4530 E_OBJECT_CHECK(ec);
4531 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4532 if (!ec->zone) return;
4533 if ((ec->shaded) || (ec->shading)) return;
4534 if (!ec->fullscreen) return;
4535 ec->pre_res_change.valid = 0;
4536 ec->fullscreen = 0;
4537 ec->need_fullscreen = 0;
4538 ec->desk->fullscreen_clients = eina_list_remove(ec->desk->fullscreen_clients, ec);
4539
4540 if (ec->fullscreen_policy == E_FULLSCREEN_ZOOM)
4541 evas_object_smart_callback_call(ec->frame, "unfullscreen_zoom", NULL);
4542
4543 if (!e_client_util_ignored_get(ec))
4544 _e_client_frame_update(ec);
4545 ec->fullscreen_policy = 0;
4546 evas_object_smart_callback_call(ec->frame, "unfullscreen", NULL);
4547
4548 if (ec->saved.maximized)
4549 {
4550 Eina_Bool maximize_anims_disabled = ec->maximize_anims_disabled;
4551 ec->changes.pos = ec->changes.size = 0;
4552 ec->maximize_anims_disabled = 1;
4553 e_client_maximize(ec,
4554 (e_config->maximize_policy & E_MAXIMIZE_TYPE) | ec->saved.maximized);
4555 ec->maximize_anims_disabled = maximize_anims_disabled;
4556 }
4557 else
4558 {
4559 if (ec->saved.frame &&
4560 (e_comp_object_frame_exists(ec->frame) || (!e_comp_object_frame_allowed(ec->frame))))
4561 e_client_util_move_resize_without_frame(ec, ec->zone->x + ec->saved.x,
4562 ec->zone->y + ec->saved.y,
4563 ec->saved.w, ec->saved.h);
4564 else
4565 evas_object_geometry_set(ec->frame, ec->zone->x + ec->saved.x,
4566 ec->zone->y + ec->saved.y,
4567 ec->saved.w, ec->saved.h);
4568 ec->saved.w = ec->saved.x = ec->saved.h = ec->saved.y = 0;
4569 ec->saved.set = ec->saved.frame = 0;
4570 }
4571
4572 evas_object_layer_set(ec->frame, ec->saved.layer);
4573
4574 e_hints_window_fullscreen_set(ec, 0);
4575 _e_client_event_simple(ec, E_EVENT_CLIENT_UNFULLSCREEN);
4576
4577 e_remember_update(ec);
4578 if (!ec->desk->fullscreen_clients)
4579 e_comp_render_queue();
4580 }
4581
4582 ///////////////////////////////////////
4583
4584
4585 E_API void
e_client_iconify(E_Client * ec)4586 e_client_iconify(E_Client *ec)
4587 {
4588 E_OBJECT_CHECK(ec);
4589 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4590 if (!ec->zone) return;
4591 if (ec->shading || ec->iconic) return;
4592 if (((ec->stack.prev || ec->stack.next)) && (!ec->stack.ignore))
4593 {
4594 Eina_List *l, *list = e_client_stack_list_prepare(ec);
4595 E_Client *child;
4596
4597 EINA_LIST_FOREACH(list, l, child)
4598 {
4599 e_client_iconify(child);
4600 }
4601 e_client_stack_list_finish(list);
4602 E_Desk *desk;
4603
4604 desk = e_desk_current_get(ec->zone);
4605 e_desk_last_focused_focus(desk);
4606 return;
4607 }
4608 ec->iconic = 1;
4609 ec->want_focus = ec->take_focus = 0;
4610 ec->changes.visible = 0;
4611 if (ec->fullscreen)
4612 ec->desk->fullscreen_clients = eina_list_remove(ec->desk->fullscreen_clients, ec);
4613 e_client_comp_hidden_set(ec, 1);
4614 if (!ec->stack.ignore)
4615 {
4616 if (!ec->new_client)
4617 {
4618 _e_client_revert_focus(ec);
4619 evas_object_hide(ec->frame);
4620 }
4621 e_client_urgent_set(ec, ec->icccm.urgent);
4622 }
4623 else
4624 {
4625 if (!ec->new_client)
4626 evas_object_hide(ec->frame);
4627 e_client_urgent_set(ec, ec->icccm.urgent);
4628 if (ec->focused)
4629 evas_object_focus_set(ec->frame, 0);
4630 }
4631
4632 _e_client_event_simple(ec, E_EVENT_CLIENT_ICONIFY);
4633
4634 if (!ec->stack.prev && !ec->stack.next)
4635 {
4636 if (e_config->transient.iconify)
4637 {
4638 E_Client *child;
4639 Eina_List *list = eina_list_clone(ec->transients);
4640
4641 EINA_LIST_FREE(list, child)
4642 e_client_iconify(child);
4643 }
4644 }
4645 e_remember_update(ec);
4646 }
4647
4648 E_API void
e_client_uniconify(E_Client * ec)4649 e_client_uniconify(E_Client *ec)
4650 {
4651 E_Desk *desk;
4652
4653 E_OBJECT_CHECK(ec);
4654 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4655 if (!ec->zone) return;
4656 if (ec->shading || (!ec->iconic)) return;
4657
4658 if (((ec->stack.prev || ec->stack.next)) && (!ec->stack.ignore))
4659 {
4660 Eina_List *l, *list = e_client_stack_list_prepare(ec);
4661 E_Client *child, *ec_focus = NULL;
4662
4663 EINA_LIST_FOREACH(list, l, child)
4664 {
4665 e_client_uniconify(child);
4666 if (!l->next) ec_focus = child;
4667 }
4668 e_client_stack_list_finish(list);
4669 evas_object_raise(ec_focus->frame);
4670 evas_object_focus_set(ec_focus->frame, 1);
4671 return;
4672 }
4673 desk = e_desk_current_get(ec->desk->zone);
4674 e_client_desk_set(ec, desk);
4675 if (!ec->stack.ignore)
4676 evas_object_raise(ec->frame);
4677 evas_object_show(ec->frame);
4678 e_client_comp_hidden_set(ec, 0);
4679 ec->deskshow = ec->iconic = 0;
4680 if (!ec->stack.ignore)
4681 evas_object_focus_set(ec->frame, 1);
4682
4683 _e_client_event_simple(ec, E_EVENT_CLIENT_UNICONIFY);
4684
4685 if (!ec->stack.prev && !ec->stack.next)
4686 {
4687 if (e_config->transient.iconify)
4688 {
4689 E_Client *child;
4690 Eina_List *list = eina_list_clone(ec->transients);
4691
4692 EINA_LIST_FREE(list, child)
4693 e_client_uniconify(child);
4694 }
4695 }
4696 e_remember_update(ec);
4697 }
4698
4699 ///////////////////////////////////////
4700
4701 E_API void
e_client_urgent_set(E_Client * ec,Eina_Bool urgent)4702 e_client_urgent_set(E_Client *ec, Eina_Bool urgent)
4703 {
4704 E_OBJECT_CHECK(ec);
4705 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4706
4707 if (urgent && e_screensaver_on_get() && e_config->screensaver_wake_on_urgent)
4708 {
4709 int x, y;
4710 ecore_evas_pointer_xy_get(e_comp->ee, &x, &y);
4711 ecore_evas_pointer_warp(e_comp->ee, x, y);
4712 e_comp_canvas_notidle();
4713 }
4714 if (!ec->zone) return;
4715
4716 urgent = !!urgent;
4717 if (urgent == ec->urgent) return;
4718 _e_client_event_property(ec, E_CLIENT_PROPERTY_URGENCY);
4719 if (urgent && (!ec->focused) && (!ec->want_focus))
4720 {
4721 e_comp_object_signal_emit(ec->frame, "e,state,urgent", "e");
4722 ec->urgent = urgent;
4723 }
4724 else
4725 {
4726 e_comp_object_signal_emit(ec->frame, "e,state,not_urgent", "e");
4727 ec->urgent = 0;
4728 }
4729 }
4730
4731 ///////////////////////////////////////
4732
4733 E_API void
e_client_stick(E_Client * ec)4734 e_client_stick(E_Client *ec)
4735 {
4736 E_Desk *desk;
4737
4738 E_OBJECT_CHECK(ec);
4739 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4740 if (!ec->zone) return;
4741 if (ec->sticky) return;
4742 desk = ec->desk;
4743 ec->desk = NULL;
4744 if (desk && ec->fullscreen)
4745 desk->fullscreen_clients = eina_list_remove(desk->fullscreen_clients, ec);
4746 ec->sticky = 1;
4747 ec->hidden = 0;
4748 e_hints_window_sticky_set(ec, 1);
4749 e_client_desk_set(ec, desk);
4750 evas_object_smart_callback_call(ec->frame, "stick", NULL);
4751
4752 if (ec->stack.prev || ec->stack.next)
4753 {
4754 if (ec->stack.ignore == 0)
4755 {
4756 Eina_List *l, *list = e_client_stack_list_prepare(ec);
4757 E_Client *child;
4758
4759 EINA_LIST_FOREACH(list, l, child)
4760 {
4761 if (child == ec) continue;
4762 child->sticky = 1;
4763 e_hints_window_sticky_set(child, 1);
4764 evas_object_show(ec->frame);
4765 }
4766 e_client_stack_list_finish(list);
4767 }
4768 }
4769 else
4770 {
4771 if (e_config->transient.desktop)
4772 {
4773 E_Client *child;
4774 Eina_List *list = eina_list_clone(ec->transients);
4775
4776 EINA_LIST_FREE(list, child)
4777 {
4778 child->sticky = 1;
4779 e_hints_window_sticky_set(child, 1);
4780 evas_object_show(ec->frame);
4781 }
4782 }
4783 }
4784
4785 _e_client_event_property(ec, E_CLIENT_PROPERTY_STICKY);
4786 e_remember_update(ec);
4787 }
4788
4789 E_API void
e_client_unstick(E_Client * ec)4790 e_client_unstick(E_Client *ec)
4791 {
4792 E_Desk *desk;
4793
4794 E_OBJECT_CHECK(ec);
4795 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4796 if (!ec->zone) return;
4797 /* Set the desk before we unstick the client */
4798 if (!ec->sticky) return;
4799 desk = e_desk_current_get(ec->zone);
4800 if (ec->desk && ec->fullscreen)
4801 ec->desk->fullscreen_clients = eina_list_remove(ec->desk->fullscreen_clients, ec);
4802 ec->desk = NULL;
4803 ec->hidden = ec->sticky = 0;
4804 e_hints_window_sticky_set(ec, 0);
4805 e_client_desk_set(ec, desk);
4806 evas_object_smart_callback_call(ec->frame, "unstick", NULL);
4807
4808 if (ec->stack.prev || ec->stack.next)
4809 {
4810 if (ec->stack.ignore == 0)
4811 {
4812 Eina_List *l, *list = e_client_stack_list_prepare(ec);
4813 E_Client *child;
4814
4815 EINA_LIST_FOREACH(list, l, child)
4816 {
4817 if (child == ec) continue;
4818 child->sticky = 1;
4819 e_hints_window_sticky_set(child, 0);
4820 }
4821 e_client_stack_list_finish(list);
4822 }
4823 }
4824 else
4825 {
4826 if (e_config->transient.desktop)
4827 {
4828 E_Client *child;
4829 Eina_List *list = eina_list_clone(ec->transients);
4830
4831 EINA_LIST_FREE(list, child)
4832 {
4833 child->sticky = 0;
4834 e_hints_window_sticky_set(child, 0);
4835 }
4836 }
4837 }
4838
4839 _e_client_event_property(ec, E_CLIENT_PROPERTY_STICKY);
4840
4841 e_client_desk_set(ec, e_desk_current_get(ec->zone));
4842 e_remember_update(ec);
4843 }
4844
4845 E_API void
e_client_pinned_set(E_Client * ec,Eina_Bool set)4846 e_client_pinned_set(E_Client *ec, Eina_Bool set)
4847 {
4848 E_Layer layer;
4849
4850 EINA_SAFETY_ON_NULL_RETURN(ec);
4851 ec->borderless = !!set;
4852 ec->user_skip_winlist = !!set;
4853 if (set)
4854 layer = E_LAYER_CLIENT_BELOW;
4855 else
4856 layer = E_LAYER_CLIENT_NORMAL;
4857
4858 evas_object_layer_set(ec->frame, layer);
4859
4860 ec->border.changed = 1;
4861 EC_CHANGED(ec);
4862 }
4863
4864 E_API void
e_client_prop_misc_changed(E_Client * ec)4865 e_client_prop_misc_changed(E_Client *ec)
4866 {
4867 EINA_SAFETY_ON_NULL_RETURN(ec);
4868 _e_client_event_property(ec, E_CLIENT_PROPERTY_MISC);
4869 }
4870
4871 ///////////////////////////////////////
4872
4873 E_API Eina_Bool
e_client_border_set(E_Client * ec,const char * name)4874 e_client_border_set(E_Client *ec, const char *name)
4875 {
4876 Eina_Stringshare *pborder;
4877
4878 E_OBJECT_CHECK_RETURN(ec, EINA_FALSE);
4879 E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, EINA_FALSE);
4880 if ((!e_comp_object_frame_allowed(ec->frame)) && (!e_comp_object_frame_exists(ec->frame)))
4881 return EINA_FALSE;
4882 if (ec->border.changed)
4883 CRI("CALLING WHEN border.changed SET!");
4884
4885 if (eina_streq(ec->border.name, name)) return EINA_TRUE;
4886 if (ec->mwm.borderless && (!eina_streq(name, "borderless")))
4887 {
4888 e_util_dialog_show(_("Client Error!"), _("Something has attempted to set a border when it shouldn't! Report this!"));
4889 CRI("border change attempted for MWM borderless client!");
4890 }
4891 if ((!ec->border.name) && eina_streq(name, "borderless")) return EINA_TRUE;
4892 pborder = ec->border.name;
4893 ec->border.name = eina_stringshare_add(name);
4894 if (e_comp_object_frame_theme_set(ec->frame, name))
4895 {
4896 eina_stringshare_del(pborder);
4897 return EINA_TRUE;
4898 }
4899 eina_stringshare_del(ec->border.name);
4900 ec->border.name = pborder;
4901 return EINA_FALSE;
4902 }
4903
4904 ///////////////////////////////////////
4905
4906 E_API void
e_client_comp_hidden_set(E_Client * ec,Eina_Bool hidden)4907 e_client_comp_hidden_set(E_Client *ec, Eina_Bool hidden)
4908 {
4909 E_OBJECT_CHECK(ec);
4910 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4911 if (!ec->zone) return;
4912
4913 hidden = !!hidden;
4914 if (ec->comp_hidden == hidden) return;
4915 ec->comp_hidden = hidden;
4916 evas_object_smart_callback_call(ec->frame, "comp_hidden", NULL);
4917 }
4918
4919 ///////////////////////////////////////
4920
4921 E_API void
e_client_act_move_keyboard(E_Client * ec)4922 e_client_act_move_keyboard(E_Client *ec)
4923 {
4924 EINA_SAFETY_ON_NULL_RETURN(ec);
4925 if (!ec->zone) return;
4926
4927 if (!_e_client_move_begin(ec))
4928 return;
4929 _e_client_action_init(ec);
4930 if (!_e_client_hook_call(E_CLIENT_HOOK_MOVE_UPDATE, ec)) return;
4931
4932 if (!action_handler_key)
4933 action_handler_key = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, _e_client_move_key_down, NULL);
4934
4935 if (!action_handler_mouse)
4936 action_handler_mouse = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, _e_client_move_mouse_down, NULL);
4937 _e_client_action_move_timeout_add();
4938 }
4939
4940 E_API void
e_client_act_resize_keyboard(E_Client * ec)4941 e_client_act_resize_keyboard(E_Client *ec)
4942 {
4943 EINA_SAFETY_ON_NULL_RETURN(ec);
4944 if (!ec->zone) return;
4945
4946 ec->resize_mode = E_POINTER_RESIZE_BR;
4947 ec->keyboard_resizing = 1;
4948 if (!e_client_resize_begin(ec))
4949 {
4950 ec->keyboard_resizing = 0;
4951 return;
4952 }
4953 _e_client_action_init(ec);
4954
4955 if (!action_handler_key)
4956 action_handler_key = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, _e_client_resize_key_down, NULL);
4957
4958 if (!action_handler_mouse)
4959 action_handler_mouse = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, _e_client_resize_mouse_down, NULL);
4960 _e_client_action_resize_timeout_add();
4961 }
4962
4963 E_API void
e_client_act_move_begin(E_Client * ec,E_Binding_Event_Mouse_Button * ev)4964 e_client_act_move_begin(E_Client *ec, E_Binding_Event_Mouse_Button *ev)
4965 {
4966 E_OBJECT_CHECK(ec);
4967 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4968 if (!ec->zone) return;
4969 if (e_client_util_resizing_get(ec) || (ec->moving)) return;
4970 if (ev)
4971 {
4972 char source[256];
4973
4974 snprintf(source, sizeof(source) - 1, "mouse,down,%i", ev->button);
4975 _e_client_moveinfo_gather(ec, source);
4976 }
4977 if (!_e_client_move_begin(ec))
4978 return;
4979
4980 _e_client_action_init(ec);
4981 e_pointer_mode_push(ec, E_POINTER_MOVE);
4982 }
4983
4984 E_API void
e_client_act_move_end(E_Client * ec,E_Binding_Event_Mouse_Button * ev EINA_UNUSED)4985 e_client_act_move_end(E_Client *ec, E_Binding_Event_Mouse_Button *ev EINA_UNUSED)
4986 {
4987 E_OBJECT_CHECK(ec);
4988 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4989 if (!ec->zone) return;
4990 if (!ec->moving) return;
4991 e_zone_edge_enable();
4992 _e_client_move_end(ec);
4993 e_zone_flip_coords_handle(ec->zone, -1, -1);
4994 _e_client_action_finish();
4995 }
4996
4997 E_API void
e_client_act_resize_begin(E_Client * ec,E_Binding_Event_Mouse_Button * ev)4998 e_client_act_resize_begin(E_Client *ec, E_Binding_Event_Mouse_Button *ev)
4999 {
5000 E_OBJECT_CHECK(ec);
5001 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5002 if (!ec->zone) return;
5003 if (ec->lock_user_size || ec->shaded || ec->shading) return;
5004 if (e_client_util_resizing_get(ec) || (ec->moving)) return;
5005 if (ev)
5006 {
5007 char source[256];
5008
5009 snprintf(source, sizeof(source) - 1, "mouse,down,%i", ev->button);
5010 _e_client_moveinfo_gather(ec, source);
5011 }
5012 if ((ec->mouse.current.mx > (ec->x + ec->w / 5)) &&
5013 (ec->mouse.current.mx < (ec->x + ec->w * 4 / 5)))
5014 {
5015 if (ec->mouse.current.my < (ec->y + ec->h / 2))
5016 {
5017 ec->resize_mode = E_POINTER_RESIZE_T;
5018 }
5019 else
5020 {
5021 ec->resize_mode = E_POINTER_RESIZE_B;
5022 }
5023 }
5024 else if (ec->mouse.current.mx < (ec->x + ec->w / 2))
5025 {
5026 if ((ec->mouse.current.my > (ec->y + ec->h / 5)) &&
5027 (ec->mouse.current.my < (ec->y + ec->h * 4 / 5)))
5028 {
5029 ec->resize_mode = E_POINTER_RESIZE_L;
5030 }
5031 else if (ec->mouse.current.my < (ec->y + ec->h / 2))
5032 {
5033 ec->resize_mode = E_POINTER_RESIZE_TL;
5034 }
5035 else
5036 {
5037 ec->resize_mode = E_POINTER_RESIZE_BL;
5038 }
5039 }
5040 else
5041 {
5042 if ((ec->mouse.current.my > (ec->y + ec->h / 5)) &&
5043 (ec->mouse.current.my < (ec->y + ec->h * 4 / 5)))
5044 {
5045 ec->resize_mode = E_POINTER_RESIZE_R;
5046 }
5047 else if (ec->mouse.current.my < (ec->y + ec->h / 2))
5048 {
5049 ec->resize_mode = E_POINTER_RESIZE_TR;
5050 }
5051 else
5052 {
5053 ec->resize_mode = E_POINTER_RESIZE_BR;
5054 }
5055 }
5056 if (!e_client_resize_begin(ec))
5057 return;
5058 _e_client_action_init(ec);
5059 e_pointer_mode_push(ec, ec->resize_mode);
5060 }
5061
5062 E_API void
e_client_act_resize_end(E_Client * ec,E_Binding_Event_Mouse_Button * ev EINA_UNUSED)5063 e_client_act_resize_end(E_Client *ec, E_Binding_Event_Mouse_Button *ev EINA_UNUSED)
5064 {
5065 E_OBJECT_CHECK(ec);
5066 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5067 if (!ec->zone) return;
5068 if (e_client_util_resizing_get(ec))
5069 {
5070 _e_client_resize_end(ec);
5071 ec->changes.reset_gravity = 1;
5072 if (!e_object_is_del(E_OBJECT(ec)))
5073 EC_CHANGED(ec);
5074 }
5075 _e_client_action_finish();
5076 }
5077
5078 E_API void
e_client_act_menu_begin(E_Client * ec,E_Binding_Event_Mouse_Button * ev,int key)5079 e_client_act_menu_begin(E_Client *ec, E_Binding_Event_Mouse_Button *ev, int key)
5080 {
5081 E_OBJECT_CHECK(ec);
5082 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5083 if (!ec->zone) return;
5084 if (ec->border_menu) return;
5085 if (ev)
5086 e_int_client_menu_show(ec, ev->canvas.x, ev->canvas.y, key, ev->timestamp);
5087 else
5088 {
5089 int x, y;
5090
5091 evas_pointer_canvas_xy_get(e_comp->evas, &x, &y);
5092 e_int_client_menu_show(ec, x, y, key, 0);
5093 }
5094 }
5095
5096 E_API void
e_client_act_close_begin(E_Client * ec)5097 e_client_act_close_begin(E_Client *ec)
5098 {
5099 E_OBJECT_CHECK(ec);
5100 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5101 if (!ec->zone) return;
5102 if (ec->lock_close) return;
5103 if (ec->icccm.delete_request)
5104 {
5105 ec->delete_requested = 1;
5106 evas_object_smart_callback_call(ec->frame, "delete_request", NULL);
5107 }
5108 else if (e_config->kill_if_close_not_possible)
5109 {
5110 e_client_act_kill_begin(ec);
5111 }
5112 }
5113
5114 E_API void
e_client_act_kill_begin(E_Client * ec)5115 e_client_act_kill_begin(E_Client *ec)
5116 {
5117 E_OBJECT_CHECK(ec);
5118 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5119 if (!ec->zone) return;
5120 if (ec->internal) return;
5121 if (ec->lock_close) return;
5122 if (ec->netwm.pid == getpid()) return;
5123 if ((ec->netwm.pid > 1) && (e_config->kill_process))
5124 {
5125 kill(ec->netwm.pid, SIGINT);
5126 ec->kill_timer = ecore_timer_loop_add(e_config->kill_timer_wait,
5127 _e_client_cb_kill_timer, ec);
5128 }
5129 else
5130 evas_object_smart_callback_call(ec->frame, "kill_request", NULL);
5131 }
5132
5133 ////////////////////////////////////////////////
5134
5135
5136 E_API Evas_Object *
e_client_icon_add(E_Client * ec,Evas * evas)5137 e_client_icon_add(E_Client *ec, Evas *evas)
5138 {
5139 Evas_Object *o;
5140
5141 E_OBJECT_CHECK_RETURN(ec, NULL);
5142 E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, NULL);
5143
5144 o = NULL;
5145 if (ec->internal)
5146 {
5147 if (!ec->internal_icon)
5148 {
5149 o = e_icon_add(evas);
5150 e_util_icon_theme_set(o, "enlightenment");
5151 }
5152 else
5153 {
5154 if (!ec->internal_icon_key)
5155 {
5156 char *ext;
5157
5158 ext = strrchr(ec->internal_icon, '.');
5159 if ((ext) && ((!strcmp(ext, ".edj"))))
5160 {
5161 o = edje_object_add(evas);
5162 if (!edje_object_file_set(o, ec->internal_icon, "icon"))
5163 e_util_icon_theme_set(o, "enlightenment");
5164 }
5165 else if (ext)
5166 {
5167 o = e_icon_add(evas);
5168 e_icon_file_set(o, ec->internal_icon);
5169 }
5170 else
5171 {
5172 o = e_icon_add(evas);
5173 if (!e_util_icon_theme_set(o, ec->internal_icon))
5174 e_util_icon_theme_set(o, "enlightenment");
5175 }
5176 }
5177 else
5178 {
5179 o = edje_object_add(evas);
5180 edje_object_file_set(o, ec->internal_icon,
5181 ec->internal_icon_key);
5182 }
5183 }
5184 return o;
5185 }
5186 #ifndef HAVE_WAYLAND_ONLY
5187 if ((e_config->use_app_icon) && (ec->icon_preference != E_ICON_PREF_USER))
5188 {
5189 if (ec->netwm.icons)
5190 {
5191 o = e_icon_add(evas);
5192 e_icon_data_set(o, ec->netwm.icons[0].data,
5193 ec->netwm.icons[0].width,
5194 ec->netwm.icons[0].height);
5195 e_icon_alpha_set(o, 1);
5196 return o;
5197 }
5198 }
5199 #endif
5200 if (!o)
5201 {
5202 if ((ec->desktop) && (ec->icon_preference != E_ICON_PREF_NETWM))
5203 {
5204 o = e_util_desktop_icon_add(ec->desktop, 64, evas);
5205 if (o)
5206 return o;
5207 }
5208 #ifndef HAVE_WAYLAND_ONLY
5209 else if (ec->netwm.icons)
5210 {
5211 o = e_icon_add(evas);
5212 e_icon_data_set(o, ec->netwm.icons[0].data,
5213 ec->netwm.icons[0].width,
5214 ec->netwm.icons[0].height);
5215 e_icon_alpha_set(o, 1);
5216 return o;
5217 }
5218 #endif
5219 }
5220
5221 o = e_icon_add(evas);
5222 e_util_icon_theme_set(o, "unknown");
5223 return o;
5224 }
5225
5226 ////////////////////////////////////////////
5227
5228 E_API void
e_client_ping(E_Client * ec)5229 e_client_ping(E_Client *ec)
5230 {
5231 E_OBJECT_CHECK(ec);
5232 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5233 if (!e_config->ping_clients) return;
5234 ec->ping_ok = 0;
5235 evas_object_smart_callback_call(ec->frame, "ping", NULL);
5236 ec->ping = ecore_loop_time_get();
5237 if (ec->ping_poller) ecore_poller_del(ec->ping_poller);
5238 ec->ping_poller = ecore_poller_add(ECORE_POLLER_CORE,
5239 e_config->ping_clients_interval,
5240 _e_client_cb_ping_poller, ec);
5241 }
5242
5243 ////////////////////////////////////////////
5244
5245 E_API void
e_client_move_cancel(void)5246 e_client_move_cancel(void)
5247 {
5248 if (!ecmove) return;
5249 if (ecmove->cur_mouse_action)
5250 {
5251 E_Client *ec;
5252
5253 ec = ecmove;
5254 e_object_ref(E_OBJECT(ec));
5255 _e_client_mouse_action_end(ec);
5256 e_object_unref(E_OBJECT(ec));
5257 }
5258 else
5259 _e_client_move_end(ecmove);
5260 }
5261
5262 E_API void
e_client_resize_cancel(void)5263 e_client_resize_cancel(void)
5264 {
5265 if (!ecresize) return;
5266 if (ecresize->cur_mouse_action)
5267 {
5268 E_Client *ec;
5269
5270 ec = ecresize;
5271 e_object_ref(E_OBJECT(ec));
5272 _e_client_mouse_action_end(ec);
5273 e_object_unref(E_OBJECT(ec));
5274 }
5275 else
5276 _e_client_resize_end(ecresize);
5277 }
5278
5279 E_API Eina_Bool
e_client_resize_begin(E_Client * ec)5280 e_client_resize_begin(E_Client *ec)
5281 {
5282 if ((ec->shaded) || (ec->shading) ||
5283 (ec->fullscreen) || (ec->lock_user_size))
5284 goto error;
5285 if (!_e_client_action_input_win_new()) goto error;
5286 if (!ec->lock_user_stacking)
5287 {
5288 if (e_config->border_raise_on_mouse_action)
5289 evas_object_raise(ec->frame);
5290 }
5291 ecresize = ec;
5292 _e_client_hook_call(E_CLIENT_HOOK_RESIZE_BEGIN, ec);
5293 if (!e_client_util_resizing_get(ec))
5294 {
5295 if (ecresize == ec) ecresize = NULL;
5296 _e_client_action_input_win_del();
5297 return EINA_FALSE;
5298 }
5299 E_FREE_FUNC(ec->raise_timer, ecore_timer_del);
5300 _e_client_action_event_grabber_init(ec);
5301 return EINA_TRUE;
5302 error:
5303 ec->resize_mode = E_POINTER_RESIZE_NONE;
5304 return EINA_FALSE;
5305 }
5306
5307
5308 ////////////////////////////////////////////
5309
5310 E_API void
e_client_frame_recalc(E_Client * ec)5311 e_client_frame_recalc(E_Client *ec)
5312 {
5313 EINA_SAFETY_ON_NULL_RETURN(ec);
5314 if (!ec->frame) return;
5315 evas_object_smart_callback_call(ec->frame, "frame_recalc", NULL);
5316 }
5317
5318 ////////////////////////////////////////////
5319
5320 E_API void
e_client_signal_move_begin(E_Client * ec,const char * sig,const char * src EINA_UNUSED)5321 e_client_signal_move_begin(E_Client *ec, const char *sig, const char *src EINA_UNUSED)
5322 {
5323 E_OBJECT_CHECK(ec);
5324 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5325 if (!ec->zone) return;
5326
5327 if (e_client_util_resizing_get(ec) || (ec->moving)) return;
5328 _e_client_moveinfo_gather(ec, sig);
5329 if (!_e_client_move_begin(ec)) return;
5330 _e_client_action_init(ec);
5331 e_pointer_mode_push(ec, E_POINTER_MOVE);
5332 }
5333
5334 E_API void
e_client_signal_move_end(E_Client * ec,const char * sig EINA_UNUSED,const char * src EINA_UNUSED)5335 e_client_signal_move_end(E_Client *ec, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
5336 {
5337 E_OBJECT_CHECK(ec);
5338 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5339 if (!ec->zone) return;
5340 if (!ec->moving) return;
5341 _e_client_move_end(ec);
5342 e_zone_edge_enable();
5343 e_zone_flip_coords_handle(ec->zone, -1, -1);
5344 _e_client_action_finish();
5345 }
5346
5347 E_API void
e_client_signal_resize_begin(E_Client * ec,const char * dir,const char * sig,const char * src EINA_UNUSED)5348 e_client_signal_resize_begin(E_Client *ec, const char *dir, const char *sig, const char *src EINA_UNUSED)
5349 {
5350 int resize_mode = E_POINTER_RESIZE_BR;
5351
5352 E_OBJECT_CHECK(ec);
5353 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5354
5355 if (e_client_util_resizing_get(ec) || (ec->moving)) return;
5356 if (!strcmp(dir, "tl"))
5357 {
5358 resize_mode = E_POINTER_RESIZE_TL;
5359 }
5360 else if (!strcmp(dir, "t"))
5361 {
5362 resize_mode = E_POINTER_RESIZE_T;
5363 }
5364 else if (!strcmp(dir, "tr"))
5365 {
5366 resize_mode = E_POINTER_RESIZE_TR;
5367 }
5368 else if (!strcmp(dir, "r"))
5369 {
5370 resize_mode = E_POINTER_RESIZE_R;
5371 }
5372 else if (!strcmp(dir, "br"))
5373 {
5374 resize_mode = E_POINTER_RESIZE_BR;
5375 }
5376 else if (!strcmp(dir, "b"))
5377 {
5378 resize_mode = E_POINTER_RESIZE_B;
5379 }
5380 else if (!strcmp(dir, "bl"))
5381 {
5382 resize_mode = E_POINTER_RESIZE_BL;
5383 }
5384 else if (!strcmp(dir, "l"))
5385 {
5386 resize_mode = E_POINTER_RESIZE_L;
5387 }
5388 ec->resize_mode = resize_mode;
5389 _e_client_moveinfo_gather(ec, sig);
5390 if (!e_client_resize_begin(ec))
5391 return;
5392 _e_client_action_init(ec);
5393 e_pointer_mode_push(ec, ec->resize_mode);
5394 }
5395
5396 E_API void
e_client_signal_resize_end(E_Client * ec,const char * dir EINA_UNUSED,const char * sig EINA_UNUSED,const char * src EINA_UNUSED)5397 e_client_signal_resize_end(E_Client *ec, const char *dir EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
5398 {
5399 E_OBJECT_CHECK(ec);
5400 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5401 if (!e_client_util_resizing_get(ec)) return;
5402 _e_client_resize_handle(ec);
5403 _e_client_resize_end(ec);
5404 ec->changes.reset_gravity = 1;
5405 EC_CHANGED(ec);
5406 _e_client_action_finish();
5407 }
5408
5409 ////////////////////////////////////////////
5410
5411 E_API void
e_client_resize_limit(const E_Client * ec,int * w,int * h)5412 e_client_resize_limit(const E_Client *ec, int *w, int *h)
5413 {
5414 int l = 0, r = 0, t = 0, b = 0;
5415 int dw = 0, dh = 0;
5416 E_OBJECT_CHECK(ec);
5417 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5418
5419 e_comp_object_frame_geometry_get(ec->frame, &l, &r, &t, &b);
5420 if ((ec->frame) && e_comp_object_frame_allowed(ec->frame))
5421 {
5422 e_comp_object_frame_wh_unadjust(ec->frame, ec->w, ec->h, &dw, &dh);
5423 e_comp_object_frame_wh_unadjust(ec->frame, *w, *h, w, h);
5424 }
5425 else
5426 {
5427 *w -= l + r;
5428 *h -= t + b;
5429 dw = ec->w;
5430 dh = ec->h;
5431 }
5432 dw = abs(*w - dw);
5433 dh = abs(*h - dh);
5434 if (*h < 1) *h = 1;
5435 if (*w < 1) *w = 1;
5436
5437 if ((ec->icccm.max_w > 0) && (*w > ec->icccm.max_w)) *w = ec->icccm.max_w;
5438 else if (*w < ec->icccm.min_w)
5439 *w = ec->icccm.min_w;
5440 if ((ec->icccm.max_h > 0) && (*h > ec->icccm.max_h)) *h = ec->icccm.max_h;
5441 else if (*h < ec->icccm.min_h)
5442 *h = ec->icccm.min_h;
5443
5444 if (ec->icccm.step_w > 0)
5445 {
5446 int bw = ec->icccm.base_w ?: ec->icccm.min_w;
5447
5448 bw = bw + (((*w - bw) / ec->icccm.step_w) * ec->icccm.step_w);
5449 if ((bw > ec->icccm.min_w) && ((ec->icccm.max_w < 1) || (bw < ec->icccm.max_w)))
5450 *w = bw;
5451 }
5452 if (ec->icccm.step_h > 0)
5453 {
5454 int bh = ec->icccm.base_h ?: ec->icccm.min_h;
5455
5456 bh = bh + (((*h - bh) / ec->icccm.step_h) * ec->icccm.step_h);
5457 if ((bh > ec->icccm.min_h) && ((ec->icccm.max_h < 1) || (bh < ec->icccm.max_h)))
5458 *h = bh;
5459 }
5460
5461 if (EINA_DBL_NONZERO(ec->icccm.min_aspect) ||
5462 EINA_DBL_NONZERO(ec->icccm.max_aspect))
5463 {
5464 double a = (double)*w / *h;
5465 Evas_Aspect_Control aspect;
5466 int aw, ah;
5467 double val;
5468
5469 if (a < ec->icccm.min_aspect)
5470 {
5471 if (dw)
5472 aspect = EVAS_ASPECT_CONTROL_HORIZONTAL;
5473 else if (dh)
5474 aspect = EVAS_ASPECT_CONTROL_VERTICAL;
5475 else
5476 aspect = EVAS_ASPECT_CONTROL_BOTH;
5477 switch (aspect)
5478 {
5479 case EVAS_ASPECT_CONTROL_HORIZONTAL:
5480 val = ((*h - (*w / ec->icccm.min_aspect)) * ec->icccm.step_h) / ec->icccm.step_h;
5481 if (val > 0)
5482 ah = ceil(val);
5483 else
5484 ah = floor(val);
5485 if (*h - ah > ec->icccm.min_h)
5486 {
5487 *h -= ah;
5488 break;
5489 }
5490 EINA_FALLTHROUGH;
5491 /* No break */
5492 default:
5493 val = (((*h * ec->icccm.min_aspect) - *w) * ec->icccm.step_w) / ec->icccm.step_w;
5494 if (val > 0)
5495 aw = ceil(val);
5496 else
5497 aw = floor(val);
5498 if (*w + aw < ec->icccm.max_w)
5499 *w += aw;
5500 break;
5501 }
5502 }
5503 a = (double)*w / *h;
5504 if (a < ec->icccm.min_aspect) abort();
5505 if (a > ec->icccm.max_aspect)
5506 {
5507 if (dw)
5508 aspect = EVAS_ASPECT_CONTROL_HORIZONTAL;
5509 else if (dh)
5510 aspect = EVAS_ASPECT_CONTROL_VERTICAL;
5511 else
5512 aspect = EVAS_ASPECT_CONTROL_BOTH;
5513 switch (aspect)
5514 {
5515 case EVAS_ASPECT_CONTROL_HORIZONTAL:
5516 val = (((*w / ec->icccm.max_aspect) - *h) * ec->icccm.step_h) / ec->icccm.step_h;
5517 if (val > 0)
5518 ah = ceil(val);
5519 else
5520 ah = floor(val);
5521 if (*h + ah > ec->icccm.max_h)
5522 {
5523 *h += ah;
5524 break;
5525 }
5526 EINA_FALLTHROUGH;
5527 /* No break */
5528 default:
5529 val = ((*w - (*h * ec->icccm.max_aspect)) * ec->icccm.step_w) / ec->icccm.step_w;
5530 if (val > 0)
5531 aw = ceil(val);
5532 else
5533 aw = floor(val);
5534 if (*w - aw > ec->icccm.min_w)
5535 *w -= aw;
5536 break;
5537 }
5538 }
5539 }
5540
5541 if (*h < 1) *h = 1;
5542 if (*w < 1) *w = 1;
5543
5544 if ((ec->frame) && e_comp_object_frame_allowed(ec->frame))
5545 {
5546 if (ec->frame)
5547 e_comp_object_frame_wh_adjust(ec->frame, *w, *h, w, h);
5548 }
5549 else
5550 {
5551 *w += l + r;
5552 *h += t + b;
5553 }
5554 }
5555
5556 ////////////////////////////////////////////
5557
5558
5559
5560 E_API E_Client *
e_client_under_pointer_get(E_Desk * desk,E_Client * exclude)5561 e_client_under_pointer_get(E_Desk *desk, E_Client *exclude)
5562 {
5563 int x, y;
5564
5565 /* We need to ensure that we can get the comp window for the
5566 * zone of either the given desk or the desk of the excluded
5567 * window, so return if neither is given */
5568 if (desk)
5569 ecore_evas_pointer_xy_get(e_comp->ee, &x, &y);
5570 else if (exclude)
5571 ecore_evas_pointer_xy_get(e_comp->ee, &x, &y);
5572 else
5573 return NULL;
5574
5575 if (!desk)
5576 {
5577 desk = exclude->desk;
5578 if (!desk)
5579 {
5580 if (exclude->zone)
5581 desk = e_desk_current_get(exclude->zone);
5582 else
5583 desk = e_desk_current_get(e_zone_current_get());
5584 }
5585 }
5586
5587 return _e_client_under_pointer_helper(desk, exclude, x, y);
5588 }
5589
5590 ////////////////////////////////////////////
5591
5592 E_API int
e_client_pointer_warp_to_center_now(E_Client * ec)5593 e_client_pointer_warp_to_center_now(E_Client *ec)
5594 {
5595 if (e_config->disable_all_pointer_warps) return 0;
5596 if (warp_client == ec)
5597 {
5598 ecore_evas_pointer_warp(e_comp->ee, warp_to_x, warp_to_y);
5599 warp_to = 0;
5600 _e_client_pointer_warp_to_center_timer(NULL);
5601 }
5602 else
5603 {
5604 if (e_client_pointer_warp_to_center(ec))
5605 e_client_pointer_warp_to_center_now(ec);
5606 }
5607 return 1;
5608 }
5609
5610 E_API int
e_client_pointer_warp_to_center(E_Client * ec)5611 e_client_pointer_warp_to_center(E_Client *ec)
5612 {
5613 int x, y;
5614 E_Client *cec = NULL;
5615
5616 ec = e_client_stack_active_adjust(ec);
5617 if (ec->override) return 0;
5618 if (!ec->zone) return 0;
5619 if (e_config->disable_all_pointer_warps) return 0;
5620 /* Only warp the pointer if it is not already in the area of
5621 * the given border */
5622 ecore_evas_pointer_xy_get(e_comp->ee, &x, &y);
5623 if ((x >= ec->x) && (x <= (ec->x + ec->w)) &&
5624 (y >= ec->y) && (y <= (ec->y + ec->h)))
5625 {
5626 cec = _e_client_under_pointer_helper(ec->desk, ec, x, y);
5627 if (cec) cec = e_client_stack_active_adjust(cec);
5628 if (cec == ec) return 0;
5629 }
5630
5631 warp_to_x = ec->x + (ec->w / 2);
5632 if (warp_to_x < (ec->zone->x + 1))
5633 warp_to_x = ec->zone->x + ((ec->x + ec->w - ec->zone->x) / 2);
5634 else if (warp_to_x > (ec->zone->x + ec->zone->w))
5635 warp_to_x = (ec->zone->x + ec->zone->w + ec->x) / 2;
5636
5637 warp_to_y = ec->y + (ec->h / 2);
5638 if (warp_to_y < (ec->zone->y + 1))
5639 warp_to_y = ec->zone->y + ((ec->y + ec->h - ec->zone->y) / 2);
5640 else if (warp_to_y > (ec->zone->y + ec->zone->h))
5641 warp_to_y = (ec->zone->y + ec->zone->h + ec->y) / 2;
5642
5643 /* TODO: handle case where another border is over the exact center,
5644 * find a place where the requested border is not overlapped?
5645 *
5646 if (!cec) cec = _e_client_under_pointer_helper(ec->desk, ec, x, y);
5647 if (cec != ec)
5648 {
5649 }
5650 */
5651
5652 warp_to = 1;
5653 warp_client = ec;
5654 ecore_evas_pointer_xy_get(e_comp->ee, &warp_x[0], &warp_y[0]);
5655 if (warp_timer) ecore_timer_del(warp_timer);
5656 warp_timer = ecore_timer_loop_add(0.01, _e_client_pointer_warp_to_center_timer, ec);
5657 return 1;
5658 }
5659
5660 ////////////////////////////////////////////
5661
5662 E_API void
e_client_redirected_set(E_Client * ec,Eina_Bool set)5663 e_client_redirected_set(E_Client *ec, Eina_Bool set)
5664 {
5665 EINA_SAFETY_ON_NULL_RETURN(ec);
5666 if (ec->input_only) return;
5667 set = !!set;
5668 if (ec->redirected == set) return;
5669 if (set)
5670 {
5671 e_client_frame_recalc(ec);
5672 if (!_e_client_hook_call(E_CLIENT_HOOK_REDIRECT, ec)) return;
5673 }
5674 else
5675 {
5676 if (!_e_client_hook_call(E_CLIENT_HOOK_UNREDIRECT, ec)) return;
5677 }
5678 e_comp_object_redirected_set(ec->frame, set);
5679 ec->redirected = !!set;
5680 }
5681
5682 ////////////////////////////////////////////
5683
5684 E_API void
e_client_next_mouse_action_ignore(E_Client * ec)5685 e_client_next_mouse_action_ignore(E_Client *ec)
5686 {
5687 EINA_SAFETY_ON_NULL_RETURN(ec);
5688 ec->next_mouse_action_ignore = EINA_TRUE;
5689 }
5690
5691 ////////////////////////////////////////////
5692
5693 E_API Eina_Bool
e_client_is_stacking(const E_Client * ec)5694 e_client_is_stacking(const E_Client *ec)
5695 {
5696 return e_comp->layers[e_comp_canvas_layer_map(ec->layer)].obj == ec->frame;
5697 }
5698
5699 E_API Eina_Bool
e_client_has_xwindow(const E_Client * ec)5700 e_client_has_xwindow(const E_Client *ec)
5701 {
5702 #ifdef HAVE_WAYLAND_ONLY
5703 (void)ec;
5704 return EINA_FALSE;
5705 #else
5706 # ifdef HAVE_WAYLAND
5707 if (!e_pixmap_is_x(ec->pixmap))
5708 return !!e_comp_wl_client_xwayland_pixmap(ec);
5709 # endif
5710 return e_pixmap_is_x(ec->pixmap);
5711 #endif
5712 }
5713
5714 ////////////////////////////////////////////
5715
5716 E_API void
e_client_layout_cb_set(E_Client_Layout_Cb cb)5717 e_client_layout_cb_set(E_Client_Layout_Cb cb)
5718 {
5719 if (_e_client_layout_cb && cb)
5720 CRI("ATTEMPTING TO OVERWRITE EXISTING CLIENT LAYOUT HOOK!!!");
5721 _e_client_layout_cb = cb;
5722 }
5723
5724 ////////////////////////////////////////////
5725
5726 E_API void
e_client_parent_set(E_Client * ec,E_Client * parent)5727 e_client_parent_set(E_Client *ec, E_Client *parent)
5728 {
5729 // E_Client *prev;
5730
5731 E_OBJECT_CHECK(ec);
5732 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5733 if (parent)
5734 {
5735 E_OBJECT_CHECK(parent);
5736 E_OBJECT_TYPE_CHECK(parent, E_CLIENT_TYPE);
5737 }
5738
5739 if (ec == parent)
5740 {
5741 ERR("refusing to set client as its own parent");
5742 return;
5743 }
5744
5745 if (parent && (parent->parent == ec))
5746 {
5747 ERR("refusing to set client as its parent's parent");
5748 return;
5749 }
5750
5751 if (ec->parent == parent) return;
5752
5753 /* If we already have a parent, remove it */
5754 if (ec->parent)
5755 {
5756 ec->parent->transients = eina_list_remove(ec->parent->transients, ec);
5757 if (ec->parent->modal == ec) ec->parent->modal = NULL;
5758 ec->parent = NULL;
5759 }
5760 if (parent)
5761 {
5762 // prev = eina_list_last_data_get(parent->transients);
5763 parent->transients = eina_list_append(parent->transients, ec);
5764 ec->parent = parent;
5765 }
5766 if (ec->parent)
5767 {
5768 evas_object_layer_set(ec->frame, ec->parent->layer);
5769
5770 /* complex stacking right above one dialog after the other hurts the
5771 * simple assumptions that the window should be on top by clients so
5772 * be dumber and disable this
5773 if (prev)
5774 evas_object_stack_above(ec->frame, prev->frame);
5775 else
5776 evas_object_stack_above(ec->frame, parent->frame);
5777 */
5778 evas_object_raise(ec->frame);
5779
5780 if (e_client_util_ignored_get(ec)) return;
5781 if (e_pixmap_usable_get(ec->pixmap) && (!ec->lock_user_location))
5782 e_comp_object_util_center_on(ec->frame, parent->frame);
5783
5784 if ((e_config->focus_setting == E_FOCUS_NEW_DIALOG) ||
5785 (ec->parent->focused && (e_config->focus_setting == E_FOCUS_NEW_DIALOG_IF_OWNER_FOCUSED)))
5786 ec->take_focus = 1;
5787 }
5788 }
5789
5790 static void
_e_client_stack_top(E_Client * ec_base EINA_UNUSED,E_Client * ec_stack,E_Client * ec_above)5791 _e_client_stack_top(E_Client *ec_base EINA_UNUSED,
5792 E_Client *ec_stack, E_Client *ec_above)
5793 {
5794 /* complex stacking right above one dialog after the other hurts the
5795 * simple assumptions that the window should be on top by clients so
5796 * be dumber and disable this
5797 if (!ec_above)
5798 {
5799 evas_object_raise(ec_stack->frame);
5800 evas_object_stack_above(ec_base->frame, ec_stack->frame);
5801 }
5802 else
5803 {
5804 if (ec_above->transients)
5805 {
5806 e_client_transients_restack(ec_above);
5807 E_Client *ec_last = eina_list_last_data_get(ec_above->transients);
5808 if (ec_last)
5809 evas_object_stack_above(ec_stack->frame, ec_last->frame);
5810 else
5811 evas_object_stack_above(ec_stack->frame, ec_above->frame);
5812 }
5813 else
5814 evas_object_stack_above(ec_stack->frame, ec_above->frame);
5815 }
5816 */
5817 if (!ec_above) evas_object_raise(ec_stack->frame);
5818 else
5819 {
5820 if (ec_above->transients) e_client_transients_restack(ec_above);
5821 evas_object_raise(ec_stack->frame);
5822 }
5823 }
5824
5825 E_API void
e_client_transients_restack(E_Client * ec)5826 e_client_transients_restack(E_Client *ec)
5827 {
5828 E_Client *child, *below = NULL;
5829 Eina_List *list;
5830
5831 E_OBJECT_CHECK(ec);
5832 E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5833 if (!ec->transients) return;
5834
5835 list = eina_list_clone(ec->transients);
5836 EINA_LIST_FREE(list, child)
5837 {
5838 // Don't stack iconic transients. If the user wants these shown,
5839 // that's another option.
5840 if (child->iconic) continue;
5841 _e_client_stack_top(ec, child, below);
5842 below = child;
5843 }
5844 }
5845