1 #include "e.h"
2 #include "e_mod_main.h"
3
4 /* local subsystem functions */
5 typedef struct _E_Winlist_Win E_Winlist_Win;
6
7 struct _E_Winlist_Win
8 {
9 Evas_Object *bg_object;
10 Evas_Object *icon_object;
11 E_Client *client;
12 unsigned char was_iconified E_BITFIELD;
13 unsigned char was_shaded E_BITFIELD;
14 };
15
16 static void _e_winlist_size_adjust(void);
17 static Eina_Bool _e_winlist_client_add(E_Client *ec, E_Zone *zone, E_Desk *desk);
18 static void _e_winlist_client_del(E_Client *ec);
19 static void _e_winlist_activate_nth(int n);
20 static void _e_winlist_activate(void);
21 static void _e_winlist_deactivate(void);
22 static void _e_winlist_show_active(void);
23 static Eina_Bool _e_winlist_cb_event_border_add(void *data, int type, void *event);
24 static Eina_Bool _e_winlist_cb_event_border_remove(void *data, int type, void *event);
25 static Eina_Bool _e_winlist_cb_key_down(void *data, int type, void *event);
26 static Eina_Bool _e_winlist_cb_key_up(void *data, int type, void *event);
27 static Eina_Bool _e_winlist_cb_mouse_down(void *data, int type, void *event);
28 static Eina_Bool _e_winlist_cb_mouse_up(void *data, int type, void *event);
29 static Eina_Bool _e_winlist_cb_mouse_wheel(void *data, int type, void *event);
30 static Eina_Bool _e_winlist_cb_mouse_move(void *data, int type, void *event);
31 static Eina_Bool _e_winlist_scroll_timer(void *data);
32 static Eina_Bool _e_winlist_animator(void *data);
33 #if 0
34 static void _e_winlist_cb_item_mouse_in(void *data, Evas *evas,
35 Evas_Object *obj, void *event_info);
36 #endif
37
38 /* local subsystem globals */
39 static Evas_Object *_winlist = NULL;
40 static E_Zone *_winlist_zone = NULL;
41 static Evas_Object *_bg_object = NULL;
42 static Evas_Object *_list_object = NULL;
43 static Evas_Object *_icon_object = NULL;
44 static Eina_List *_wins = NULL;
45 static Eina_List *_win_selected = NULL;
46 static E_Desk *_last_desk = NULL;
47 static int _last_pointer_x = 0;
48 static int _last_pointer_y = 0;
49 static E_Client *_last_client = NULL;
50 static int _hold_count = 0;
51 static int _hold_mod = 0;
52 static E_Winlist_Activate_Type _activate_type = 0;
53 static Eina_List *_handlers = NULL;
54 static Ecore_Window _input_window = 0;
55 static int _scroll_to = 0;
56 static double _scroll_align_to = 0.0;
57 static double _scroll_align = 0.0;
58 static Ecore_Timer *_scroll_timer = NULL;
59 static Ecore_Animator *_animator = NULL;
60
61 static Eina_Bool
_wmclass_picked(const Eina_List * lst,const char * wmclass)62 _wmclass_picked(const Eina_List *lst, const char *wmclass)
63 {
64 const Eina_List *l;
65 const char *s;
66
67 if (!wmclass) return EINA_FALSE;
68
69 EINA_LIST_FOREACH(lst, l, s)
70 if (s == wmclass)
71 return EINA_TRUE;
72
73 return EINA_FALSE;
74 }
75
76 static void
_cb_lost(void * data EINA_UNUSED)77 _cb_lost(void *data EINA_UNUSED)
78 {
79 e_winlist_hide();
80 }
81
82 /* externally accessible functions */
83 int
e_winlist_init(void)84 e_winlist_init(void)
85 {
86 return 1;
87 }
88
89 int
e_winlist_shutdown(void)90 e_winlist_shutdown(void)
91 {
92 e_winlist_hide();
93 return 1;
94 }
95
96 int
e_winlist_show(E_Zone * zone,E_Winlist_Filter filter)97 e_winlist_show(E_Zone *zone, E_Winlist_Filter filter)
98 {
99 int x, y, w, h;
100 Evas_Object *o;
101 Eina_List *l, *ll;
102 E_Desk *desk;
103 E_Client *ec;
104 E_Winlist_Win *ww;
105 Eina_List *wmclasses = NULL;
106
107 E_OBJECT_CHECK_RETURN(zone, 0);
108 E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, 0);
109
110 if (_winlist) return 1;
111
112 #ifndef HAVE_WAYLAND_ONLY
113 if (e_comp->comp_type == E_PIXMAP_TYPE_X)
114 {
115 Ecore_X_Window mouse_grab = 0;
116 _input_window = ecore_x_window_input_new(e_comp->root, 0, 0, 1, 1);
117 ecore_x_window_show(_input_window);
118 if (_activate_type == E_WINLIST_ACTIVATE_TYPE_MOUSE)
119 mouse_grab = _input_window;
120 if (!e_grabinput_get(mouse_grab, 0, _input_window))
121 {
122 ecore_x_window_free(_input_window);
123 _input_window = 0;
124 return 0;
125 }
126 e_grabinput_lost_cb_set(_cb_lost, NULL);
127 }
128 #endif
129 if (e_comp->comp_type != E_PIXMAP_TYPE_X)
130 {
131 Eina_Bool mouse_grab = EINA_FALSE;
132 if (_activate_type == E_WINLIST_ACTIVATE_TYPE_MOUSE)
133 mouse_grab = EINA_TRUE;
134 if (!e_comp_grab_input(mouse_grab, EINA_TRUE))
135 return 0;
136 _input_window = e_comp->ee_win;
137 }
138
139 w = (double)zone->w * e_config->winlist_pos_size_w;
140 if (w > e_config->winlist_pos_max_w) w = e_config->winlist_pos_max_w;
141 else if (w < e_config->winlist_pos_min_w)
142 w = e_config->winlist_pos_min_w;
143 if (w > zone->w) w = zone->w;
144 x = zone->x + (double)(zone->w - w) * e_config->winlist_pos_align_x;
145
146 h = (double)zone->h * e_config->winlist_pos_size_h;
147 if (h > e_config->winlist_pos_max_h) h = e_config->winlist_pos_max_h;
148 else if (h < e_config->winlist_pos_min_h)
149 h = e_config->winlist_pos_min_h;
150 if (h > zone->h) h = zone->h;
151 y = zone->y + (double)(zone->h - h) * e_config->winlist_pos_align_y;
152
153 _winlist_zone = zone;
154 e_client_move_cancel();
155 e_client_resize_cancel();
156 e_client_focus_track_freeze();
157
158 #ifndef HAVE_WAYLAND_ONLY
159 evas_event_feed_mouse_in(e_comp->evas, 0, NULL);
160 evas_event_feed_mouse_move(e_comp->evas, -1000000, -1000000, 0, NULL);
161 #endif
162
163 evas_event_freeze(e_comp->evas);
164 o = edje_object_add(e_comp->evas);
165 evas_object_pass_events_set(o, EINA_TRUE);
166 _winlist = e_comp_object_util_add(o, E_COMP_OBJECT_TYPE_POPUP);
167 evas_object_layer_set(_winlist, E_LAYER_CLIENT_POPUP);
168 evas_object_move(_winlist, x, y);
169 _bg_object = o;
170 e_theme_edje_object_set(o, "base/theme/winlist",
171 "e/widgets/winlist/main");
172
173 o = elm_box_add(e_comp->elm);
174 _list_object = o;
175 elm_box_homogeneous_set(o, 1);
176 e_comp_object_util_del_list_append(_winlist, o);
177 edje_object_part_swallow(_bg_object, "e.swallow.list", o);
178 edje_object_part_text_set(_bg_object, "e.text.title", _("Select a window"));
179 evas_object_show(o);
180
181 _last_client = e_client_focused_get();
182
183 desk = e_desk_current_get(_winlist_zone);
184 EINA_LIST_FOREACH(e_client_focus_stack_get(), l, ec)
185 {
186 Eina_Bool pick;
187
188 // skip if we already have it in winlist
189 EINA_LIST_FOREACH(_wins, ll, ww)
190 {
191 if (e_client_stack_bottom_get(ww->client) ==
192 e_client_stack_bottom_get(ec)) break;
193 }
194 if (ll) continue;
195 switch (filter)
196 {
197 case E_WINLIST_FILTER_CLASS_WINDOWS:
198 if (!_last_client)
199 pick = EINA_FALSE;
200 else
201 pick = _last_client->icccm.class == ec->icccm.class;
202 break;
203 case E_WINLIST_FILTER_CLASSES:
204 pick = (!_wmclass_picked(wmclasses, ec->icccm.class));
205 if (pick)
206 wmclasses = eina_list_append(wmclasses, ec->icccm.class);
207 break;
208
209 default:
210 pick = EINA_TRUE;
211 }
212 if (pick) _e_winlist_client_add(ec, _winlist_zone, desk);
213 }
214 eina_list_free(wmclasses);
215
216 if (!_wins)
217 {
218 e_winlist_hide();
219 evas_event_thaw(e_comp->evas);
220 return 1;
221 }
222
223 if (e_config->winlist_list_show_other_desk_windows ||
224 e_config->winlist_list_show_other_screen_windows)
225 _last_desk = e_desk_current_get(_winlist_zone);
226 if (e_config->winlist_warp_while_selecting)
227 ecore_evas_pointer_xy_get(e_comp->ee,
228 &_last_pointer_x, &_last_pointer_y);
229
230 _e_winlist_activate_nth(0);
231
232 evas_event_thaw(e_comp->evas);
233 _e_winlist_size_adjust();
234
235 E_LIST_HANDLER_APPEND(_handlers, E_EVENT_CLIENT_ADD, _e_winlist_cb_event_border_add, NULL);
236 E_LIST_HANDLER_APPEND(_handlers, E_EVENT_CLIENT_REMOVE, _e_winlist_cb_event_border_remove, NULL);
237 E_LIST_HANDLER_APPEND(_handlers, ECORE_EVENT_KEY_DOWN, _e_winlist_cb_key_down, NULL);
238 E_LIST_HANDLER_APPEND(_handlers, ECORE_EVENT_KEY_UP, _e_winlist_cb_key_up, NULL);
239 E_LIST_HANDLER_APPEND(_handlers, ECORE_EVENT_MOUSE_BUTTON_DOWN, _e_winlist_cb_mouse_down, NULL);
240 E_LIST_HANDLER_APPEND(_handlers, ECORE_EVENT_MOUSE_BUTTON_UP, _e_winlist_cb_mouse_up, NULL);
241 E_LIST_HANDLER_APPEND(_handlers, ECORE_EVENT_MOUSE_WHEEL, _e_winlist_cb_mouse_wheel, NULL);
242 E_LIST_HANDLER_APPEND(_handlers, ECORE_EVENT_MOUSE_MOVE, _e_winlist_cb_mouse_move, NULL);
243
244 evas_object_show(_winlist);
245 return 1;
246 }
247
248 void
e_winlist_hide(void)249 e_winlist_hide(void)
250 {
251 E_Client *ec = NULL;
252 E_Winlist_Win *ww;
253
254 if (!_winlist) return;
255 if (_win_selected)
256 {
257 ww = _win_selected->data;
258 ec = ww->client;
259 }
260 evas_object_hide(_winlist);
261 EINA_LIST_FREE(_wins, ww)
262 {
263 if ((!ec) || (ww->client != ec))
264 e_object_unref(E_OBJECT(ww->client));
265 free(ww);
266 }
267 _win_selected = NULL;
268 _icon_object = NULL;
269
270 evas_object_del(_winlist);
271 e_client_focus_track_thaw();
272 _winlist = NULL;
273 _winlist_zone = NULL;
274 _hold_count = 0;
275 _hold_mod = 0;
276 _activate_type = 0;
277
278 E_FREE_LIST(_handlers, ecore_event_handler_del);
279
280 E_FREE_FUNC(_scroll_timer, ecore_timer_del);
281 E_FREE_FUNC(_animator, ecore_animator_del);
282
283 #ifndef HAVE_WAYLAND_ONLY
284 if (e_comp->comp_type == E_PIXMAP_TYPE_X)
285 {
286 if (_input_window)
287 {
288 e_grabinput_release(_input_window, _input_window);
289 ecore_x_window_free(_input_window);
290 }
291 }
292 #endif
293 if (e_comp->comp_type == E_PIXMAP_TYPE_WL)
294 e_comp_ungrab_input(1, 1);
295 _input_window = 0;
296 if (ec)
297 {
298 Eina_Bool set = !ec->lock_focus_out;
299
300 if (ec->shaded)
301 {
302 if (!ec->lock_user_shade)
303 e_client_unshade(ec, ec->shade_dir);
304 }
305 if (e_config->winlist_list_move_after_select)
306 {
307 e_client_zone_set(ec, e_zone_current_get());
308 e_client_desk_set(ec, e_desk_current_get(ec->zone));
309 }
310 else if (ec->desk)
311 {
312 if (!ec->sticky) e_desk_show(ec->desk);
313 }
314 if (!ec->lock_user_stacking)
315 {
316 evas_object_raise(ec->frame);
317 e_client_raise_latest_set(ec);
318 }
319 if (ec->iconic)
320 e_client_uniconify(ec);
321 if (ec->shaded)
322 e_client_unshade(ec, ec->shade_dir);
323 if ((e_config->focus_policy != E_FOCUS_CLICK) ||
324 (e_config->winlist_warp_at_end) ||
325 (e_config->winlist_warp_while_selecting))
326 {
327 set |= !e_client_pointer_warp_to_center_now(ec);
328 }
329 if (set)
330 {
331 evas_object_focus_set(ec->frame, 1);
332 e_client_focus_latest_set(ec);
333 }
334 e_object_unref(E_OBJECT(ec));
335 }
336 }
337
338 void
e_winlist_next(void)339 e_winlist_next(void)
340 {
341 if (!_winlist) return;
342 if (eina_list_count(_wins) == 1)
343 {
344 if (!_win_selected)
345 {
346 _win_selected = _wins;
347 _e_winlist_show_active();
348 _e_winlist_activate();
349 }
350 return;
351 }
352 _e_winlist_deactivate();
353 if (!_win_selected)
354 _win_selected = _wins;
355 else
356 _win_selected = _win_selected->next;
357 if (!_win_selected) _win_selected = _wins;
358 _e_winlist_show_active();
359 _e_winlist_activate();
360 }
361
362 void
e_winlist_prev(void)363 e_winlist_prev(void)
364 {
365 if (!_winlist) return;
366 if (eina_list_count(_wins) == 1)
367 {
368 if (!_win_selected)
369 {
370 _win_selected = _wins;
371 _e_winlist_show_active();
372 _e_winlist_activate();
373 }
374 return;
375 }
376 _e_winlist_deactivate();
377 if (!_win_selected)
378 _win_selected = _wins;
379 else
380 _win_selected = _win_selected->prev;
381 if (!_win_selected) _win_selected = eina_list_last(_wins);
382 _e_winlist_show_active();
383 _e_winlist_activate();
384 }
385
386 static int
point_line_dist(int x,int y,int lx1,int ly1,int lx2,int ly2)387 point_line_dist(int x, int y, int lx1, int ly1, int lx2, int ly2)
388 {
389 int xx, yy, dx, dy;
390 int a = x - lx1;
391 int b = y - ly1;
392 int c = lx2 - lx1;
393 int d = ly2 - ly1;
394
395 int dot = (a * c) + (b * d);
396 int len_sq = (c * c) + (d * d);
397 double dist, param = -1.0;
398
399 // if line is 0 length
400 if (len_sq) param = (double)dot / len_sq;
401
402 if (param < 0)
403 {
404 xx = lx1;
405 yy = ly1;
406 }
407 else if (param > 1)
408 {
409 xx = lx2;
410 yy = ly2;
411 }
412 else
413 {
414 xx = lx1 + lround(param * c);
415 yy = ly1 + lround(param * d);
416 }
417
418 dx = x - xx;
419 dy = y - yy;
420 dist = sqrt((dx * dx) + (dy * dy));
421 return lround(dist);
422 }
423
424 void
e_winlist_direction_select(E_Zone * zone,int dir)425 e_winlist_direction_select(E_Zone *zone, int dir)
426 {
427 E_Client *ec;
428 Eina_List *l;
429 E_Desk *desk;
430 E_Client *ec_orig, *ec_next = NULL;
431 int distance = INT_MAX;
432 int cx, cy;
433 E_Winlist_Win *ww;
434
435 ec_next = NULL;
436
437 E_OBJECT_CHECK(zone);
438 E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
439
440 ec_orig = e_client_focused_get();
441 if (!ec_orig) return;
442
443 cx = ec_orig->x + (ec_orig->w / 2);
444 cy = ec_orig->y + (ec_orig->h / 2);
445
446 desk = e_desk_current_get(zone);
447 EINA_LIST_FOREACH(e_client_focus_stack_get(), l, ec)
448 {
449 int a = 0, d = 0;
450
451 if (ec == ec_orig) continue;
452 if ((!ec->icccm.accepts_focus) &&
453 (!ec->icccm.take_focus)) continue;
454 if (ec->netwm.state.skip_taskbar) continue;
455 if (ec->user_skip_winlist) continue;
456 if (ec->iconic)
457 {
458 if (!e_config->winlist_list_show_iconified) continue;
459 if ((ec->zone != zone) &&
460 (!e_config->winlist_list_show_other_screen_iconified))
461 continue;
462 if ((ec->desk != desk) &&
463 (!e_config->winlist_list_show_other_desk_iconified)) continue;
464 }
465 else
466 {
467 if (ec->sticky)
468 {
469 if ((ec->zone != zone) &&
470 (!e_config->winlist_list_show_other_screen_windows))
471 continue;
472 }
473 else
474 {
475 if (ec->desk != desk)
476 {
477 if ((ec->zone) && (ec->zone != zone))
478 {
479 if (!e_config->winlist_list_show_other_screen_windows)
480 continue;
481 }
482 else if (!e_config->winlist_list_show_other_desk_windows)
483 continue;
484 }
485 }
486 }
487
488 switch (dir)
489 {
490 case 0: /* up */
491 d = point_line_dist(cx, cy,
492 ec->x, ec->y + ec->h,
493 ec->x + ec->w, ec->y + ec->h);
494 if (d >= distance) continue;
495 d = point_line_dist(cx, cy,
496 ec->x, ec->y + (ec->h / 2),
497 ec->x + ec->w, ec->y + (ec->h / 2));
498 if (d >= distance) continue;
499 if (cy <= (ec->y + (ec->h / 2))) continue;
500 a = abs(cx - (ec->x + (ec->w / 2)));
501 d += (a * a) / d;
502 if (d >= distance) continue;
503 break;
504 case 1: /* down */
505 d = point_line_dist(cx, cy,
506 ec->x, ec->y,
507 ec->x + ec->w, ec->y);
508 if (d >= distance) continue;
509 d = point_line_dist(cx, cy,
510 ec->x, ec->y + (ec->h / 2),
511 ec->x + ec->w, ec->y + (ec->h / 2));
512 if (d >= distance) continue;
513 if (cy >= (ec->y + (ec->h / 2))) continue;
514 a = abs(cx - (ec->x + (ec->w / 2)));
515 d += (a * a) / d;
516 if (d >= distance) continue;
517 break;
518 case 2: /* left */
519 d = point_line_dist(cx, cy,
520 ec->x + ec->w, ec->y,
521 ec->x + ec->w, ec->y + ec->h);
522 if (d >= distance) continue;
523 d = point_line_dist(cx, cy,
524 ec->x + (ec->w / 2), ec->y,
525 ec->x + (ec->w / 2), ec->y + ec->h);
526 if (d >= distance) continue;
527 if (cx <= (ec->x + (ec->w / 2))) continue;
528 a = abs(cy - (ec->y + (ec->h / 2)));
529 d += (a * a) / d;
530 if (d >= distance) continue;
531 break;
532 case 3: /* right */
533 d = point_line_dist(cx, cy,
534 ec->x, ec->y,
535 ec->x, ec->y + ec->h);
536 if (d >= distance) continue;
537 d = point_line_dist(cx, cy,
538 ec->x + (ec->w / 2), ec->y,
539 ec->x + (ec->w / 2), ec->y + ec->h);
540 if (d >= distance) continue;
541 if (cx >= (ec->x + (ec->w / 2))) continue;
542 a = abs(cy - (ec->y + (ec->h / 2)));
543 d += (a * a) / d;
544 if (d >= distance) continue;
545 break;
546 }
547 ec_next = ec;
548 distance = d;
549 }
550
551 if (!ec_next) return;
552 _e_winlist_deactivate();
553 EINA_LIST_FOREACH(_wins, l, ww)
554 {
555 if (ww->client != ec_next) continue;
556 _win_selected = l;
557 break;
558 }
559 _e_winlist_show_active();
560 _e_winlist_activate();
561 }
562
563 void
e_winlist_modifiers_set(int mod,E_Winlist_Activate_Type type)564 e_winlist_modifiers_set(int mod, E_Winlist_Activate_Type type)
565 {
566 _hold_mod = mod;
567 _hold_count = 0;
568 _activate_type = type;
569 if (type == E_WINLIST_ACTIVATE_TYPE_MOUSE) _hold_count++;
570 if (_hold_mod & ECORE_EVENT_MODIFIER_SHIFT) _hold_count++;
571 if (_hold_mod & ECORE_EVENT_MODIFIER_CTRL) _hold_count++;
572 if (_hold_mod & ECORE_EVENT_MODIFIER_ALT) _hold_count++;
573 if (_hold_mod & ECORE_EVENT_MODIFIER_WIN) _hold_count++;
574 }
575
576 /* local subsystem functions */
577 static void
_e_winlist_size_adjust(void)578 _e_winlist_size_adjust(void)
579 {
580 Evas_Coord mw, mh;
581 E_Zone *zone;
582 int x, y, w, h;
583
584 elm_box_recalculate(_list_object);
585 edje_object_part_swallow(_bg_object, "e.swallow.list", _list_object);
586 edje_object_size_min_calc(_bg_object, &mw, &mh);
587 evas_object_size_hint_min_set(_list_object, -1, -1);
588 edje_object_part_swallow(_bg_object, "e.swallow.list", _list_object);
589
590 zone = _winlist_zone;
591 w = (double)zone->w * e_config->winlist_pos_size_w;
592 if (w < mw) w = mw;
593 if (w > e_config->winlist_pos_max_w) w = e_config->winlist_pos_max_w;
594 else if (w < e_config->winlist_pos_min_w)
595 w = e_config->winlist_pos_min_w;
596 if (w > zone->w) w = zone->w;
597 x = zone->x + (double)(zone->w - w) * e_config->winlist_pos_align_x;
598
599 h = mh;
600 if (h > e_config->winlist_pos_max_h) h = e_config->winlist_pos_max_h;
601 else if (h < e_config->winlist_pos_min_h)
602 h = e_config->winlist_pos_min_h;
603 if (h > zone->h) h = zone->h;
604 y = zone->y + (double)(zone->h - h) * e_config->winlist_pos_align_y;
605
606 evas_object_geometry_set(_winlist, x, y, w, h);
607 }
608
609 static Eina_Bool
_e_winlist_client_add(E_Client * ec,E_Zone * zone,E_Desk * desk)610 _e_winlist_client_add(E_Client *ec, E_Zone *zone, E_Desk *desk)
611 {
612 E_Winlist_Win *ww;
613 Evas_Coord mw, mh;
614 Evas_Object *o;
615
616 if ((!ec->icccm.accepts_focus) &&
617 (!ec->icccm.take_focus)) return EINA_FALSE;
618 if (ec->netwm.state.skip_taskbar) return EINA_FALSE;
619 if (ec->user_skip_winlist) return EINA_FALSE;
620 if (ec->iconic)
621 {
622 if (!e_config->winlist_list_show_iconified) return EINA_FALSE;
623 if ((ec->zone != zone) &&
624 (!e_config->winlist_list_show_other_screen_iconified)) return EINA_FALSE;
625 if ((ec->desk != desk) &&
626 (!e_config->winlist_list_show_other_desk_iconified)) return EINA_FALSE;
627 }
628 else
629 {
630 if (ec->sticky)
631 {
632 if ((ec->zone != zone) &&
633 (!e_config->winlist_list_show_other_screen_windows)) return EINA_FALSE;
634 }
635 else
636 {
637 if (ec->desk != desk)
638 {
639 if ((ec->zone) && (ec->zone != zone))
640 {
641 if (!e_config->winlist_list_show_other_screen_windows)
642 return EINA_FALSE;
643 if (ec->zone && ec->desk && (ec->desk != e_desk_current_get(ec->zone)))
644 {
645 if (!e_config->winlist_list_show_other_desk_windows)
646 return EINA_FALSE;
647 }
648 }
649 else if (!e_config->winlist_list_show_other_desk_windows)
650 return EINA_FALSE;
651 }
652 }
653 }
654
655 ww = E_NEW(E_Winlist_Win, 1);
656 if (!ww) return EINA_FALSE;
657 ww->client = ec;
658 _wins = eina_list_append(_wins, ww);
659 o = edje_object_add(e_comp->evas);
660 E_FILL(o);
661 e_comp_object_util_del_list_append(_winlist, o);
662 ww->bg_object = o;
663 e_theme_edje_object_set(o, "base/theme/winlist",
664 "e/widgets/winlist/item");
665 edje_object_part_text_set(o, "e.text.label",
666 e_client_util_name_get
667 (e_client_stack_active_adjust(ww->client)));
668 evas_object_show(o);
669 if (edje_object_part_exists(ww->bg_object, "e.swallow.icon"))
670 {
671 o = e_client_icon_add(ec, e_comp->evas);
672 ww->icon_object = o;
673 e_comp_object_util_del_list_append(_winlist, o);
674 edje_object_part_swallow(ww->bg_object, "e.swallow.icon", o);
675 evas_object_show(o);
676 }
677 if (ec->shaded)
678 edje_object_signal_emit(ww->bg_object, "e,state,shaded", "e");
679 else if (ec->iconic)
680 edje_object_signal_emit(ww->bg_object, "e,state,iconified", "e");
681 else if (ec->desk != desk)
682 {
683 if (!((ec->sticky) && (ec->zone == zone)))
684 edje_object_signal_emit(ww->bg_object, "e,state,invisible", "e");
685 }
686
687 edje_object_size_min_calc(ww->bg_object, &mw, &mh);
688 E_WEIGHT(ww->bg_object, 1, 0);
689 E_FILL(ww->bg_object);
690 evas_object_size_hint_min_set(ww->bg_object, mw, mh);
691 evas_object_size_hint_max_set(ww->bg_object, 9999, mh);
692 elm_box_pack_end(_list_object, ww->bg_object);
693 e_object_ref(E_OBJECT(ww->client));
694 return EINA_TRUE;
695 }
696
697 static void
_e_winlist_client_del(E_Client * ec)698 _e_winlist_client_del(E_Client *ec)
699 {
700 E_Winlist_Win *ww;
701 Eina_List *l;
702
703 if (ec == _last_client) _last_client = NULL;
704 EINA_LIST_FOREACH(_wins, l, ww)
705 {
706 if (ww->client == ec)
707 {
708 e_object_unref(E_OBJECT(ww->client));
709 if (l == _win_selected)
710 {
711 _win_selected = l->next;
712 if (!_win_selected) _win_selected = l->prev;
713 _e_winlist_show_active();
714 _e_winlist_activate();
715 }
716 e_comp_object_util_del_list_remove(_winlist, ww->bg_object);
717 evas_object_del(ww->bg_object);
718 if (ww->icon_object)
719 {
720 e_comp_object_util_del_list_remove(_winlist, ww->icon_object);
721 evas_object_del(ww->icon_object);
722 }
723 E_FREE(ww);
724 _wins = eina_list_remove_list(_wins, l);
725 return;
726 }
727 }
728 }
729
730 static void
_e_winlist_client_replace(E_Client * ec,E_Client * ec_new)731 _e_winlist_client_replace(E_Client *ec, E_Client *ec_new)
732 {
733 E_Winlist_Win *ww;
734 Eina_List *l;
735
736 EINA_LIST_FOREACH(_wins, l, ww)
737 {
738 if (ww->client == ec)
739 {
740 Evas_Coord mw, mh;
741
742 edje_object_part_text_set(ww->bg_object, "e.text.label",
743 e_client_util_name_get(ec_new));
744 edje_object_size_min_calc(ww->bg_object, &mw, &mh);
745 E_WEIGHT(ww->bg_object, 1, 0);
746 E_FILL(ww->bg_object);
747 evas_object_size_hint_min_set(ww->bg_object, mw, mh);
748 evas_object_size_hint_max_set(ww->bg_object, 9999, mh);
749 return;
750 }
751 }
752 }
753
754 static void
_e_winlist_activate_nth(int n)755 _e_winlist_activate_nth(int n)
756 {
757 Eina_List *l;
758 int cnt;
759
760 _e_winlist_deactivate();
761 cnt = eina_list_count(_wins);
762 if (n >= cnt) n = cnt - 1;
763 l = eina_list_nth_list(_wins, n);
764 if (!l) return;
765
766 _win_selected = l;
767 _e_winlist_show_active();
768 _e_winlist_activate();
769 }
770
771 static void
_e_winlist_activate(void)772 _e_winlist_activate(void)
773 {
774 E_Winlist_Win *ww;
775 Evas_Object *o;
776 int ok = 0;
777
778 if (!_win_selected) return;
779 ww = _win_selected->data;
780 edje_object_signal_emit(ww->bg_object, "e,state,selected", "e");
781 if (ww->icon_object && e_icon_edje_get(ww->icon_object))
782 e_icon_edje_emit(ww->icon_object, "e,state,selected", "e");
783
784 if ((ww->client->iconic) &&
785 (e_config->winlist_list_uncover_while_selecting))
786 {
787 if (!ww->client->lock_user_iconify)
788 e_client_uniconify(ww->client);
789 ww->was_iconified = 1;
790 ok = 1;
791 }
792 if ((!ww->client->sticky) &&
793 (ww->client->desk != e_desk_current_get(_winlist_zone)) &&
794 (e_config->winlist_list_jump_desk_while_selecting))
795 {
796 if (ww->client->desk) e_desk_show(ww->client->desk);
797 ok = 1;
798 }
799 if ((ww->client->shaded || ww->client->shading) &&
800 (ww->client->desk == e_desk_current_get(_winlist_zone)) &&
801 (e_config->winlist_list_uncover_while_selecting))
802 {
803 if (!ww->client->lock_user_shade)
804 e_client_unshade(ww->client, ww->client->shade_dir);
805 ww->was_shaded = 1;
806 ok = 1;
807 }
808 if ((!ww->client->iconic) &&
809 ((ww->client->desk == e_desk_current_get(_winlist_zone)) ||
810 (ww->client->sticky)))
811 ok = 1;
812 if (ok)
813 {
814 int set = 1;
815 if (e_config->winlist_warp_while_selecting)
816 {
817 if (!e_client_pointer_warp_to_center_now(ww->client))
818 {
819 evas_object_focus_set(ww->client->frame, 1);
820 set = 0;
821 }
822 }
823
824 if ((!ww->client->lock_user_stacking) &&
825 (e_config->winlist_list_raise_while_selecting))
826 evas_object_raise(ww->client->frame);
827 if ((!ww->client->lock_focus_out) &&
828 (e_config->winlist_list_focus_while_selecting))
829 {
830 if (set)
831 evas_object_focus_set(ww->client->frame, 1);
832 }
833 }
834 edje_object_part_text_set(_bg_object, "e.text.label",
835 e_client_util_name_get(ww->client));
836 if (_icon_object)
837 {
838 e_comp_object_util_del_list_remove(_winlist, _icon_object);
839 evas_object_del(_icon_object);
840 _icon_object = NULL;
841 }
842 if (edje_object_part_exists(_bg_object, "e.swallow.icon"))
843 {
844 o = e_client_icon_add(ww->client, evas_object_evas_get(_winlist));
845 _icon_object = o;
846 e_comp_object_util_del_list_append(_winlist, o);
847 edje_object_part_swallow(_bg_object, "e.swallow.icon", o);
848 evas_object_show(o);
849 }
850
851 edje_object_signal_emit(_bg_object, "e,state,selected", "e");
852 }
853
854 static void
_e_winlist_deactivate(void)855 _e_winlist_deactivate(void)
856 {
857 E_Winlist_Win *ww;
858
859 if (!_win_selected) return;
860 ww = _win_selected->data;
861 if (ww->was_shaded)
862 {
863 if (!ww->client->lock_user_shade)
864 e_client_shade(ww->client, ww->client->shade_dir);
865 }
866 if (ww->was_iconified)
867 {
868 if (!ww->client->lock_user_iconify)
869 e_client_iconify(ww->client);
870 }
871 ww->was_shaded = 0;
872 ww->was_iconified = 0;
873 edje_object_part_text_set(_bg_object, "e.text.label", "");
874 edje_object_signal_emit(ww->bg_object, "e,state,unselected", "e");
875 if (ww->icon_object && e_icon_edje_get(ww->icon_object))
876 e_icon_edje_emit(ww->icon_object, "e,state,unselected", "e");
877 if (!ww->client->lock_focus_in)
878 evas_object_focus_set(ww->client->frame, 0);
879 }
880
881 static void
_e_winlist_show_active(void)882 _e_winlist_show_active(void)
883 {
884 Eina_List *l;
885 int i, n;
886
887 if (!_wins) return;
888
889 for (i = 0, l = _wins; l; l = l->next, i++)
890 if (l == _win_selected) break;
891
892 n = eina_list_count(_wins);
893 if (n <= 1) return;
894 _scroll_align_to = (double)i / (double)(n - 1);
895 if (e_config->winlist_scroll_animate)
896 {
897 _scroll_to = 1;
898 if (!_scroll_timer)
899 _scroll_timer = ecore_timer_loop_add(0.01, _e_winlist_scroll_timer, NULL);
900 if (!_animator)
901 _animator = ecore_animator_add(_e_winlist_animator, NULL);
902 }
903 else
904 {
905 _scroll_align = _scroll_align_to;
906 elm_box_align_set(_list_object, 0.5, fabs(1.0 - _scroll_align));
907 }
908 }
909
910 static void
_e_winlist_restore_desktop(void)911 _e_winlist_restore_desktop(void)
912 {
913 if (_last_desk &&
914 (e_config->winlist_list_show_other_desk_windows ||
915 e_config->winlist_list_show_other_screen_windows))
916 e_desk_show(_last_desk);
917 if (e_config->winlist_warp_while_selecting)
918 ecore_evas_pointer_warp(e_comp->ee,
919 _last_pointer_x, _last_pointer_y);
920 _e_winlist_deactivate();
921 _win_selected = NULL;
922 e_winlist_hide();
923 if (_last_client)
924 {
925 evas_object_focus_set(_last_client->frame, 1);
926 _last_client = NULL;
927 }
928 }
929
930 static Eina_Bool
_e_winlist_cb_event_border_add(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)931 _e_winlist_cb_event_border_add(void *data EINA_UNUSED, int type EINA_UNUSED,
932 void *event)
933 {
934 E_Event_Client *ev = event;
935 E_Client *ec = ev->ec;
936 Eina_List *l;
937 E_Winlist_Win *ww;
938
939 // get base client
940 ec = e_client_stack_bottom_get(ec);
941 // skip if we already have it in winlist
942 EINA_LIST_FOREACH(_wins, l, ww)
943 {
944 if (ww->client == ec)
945 {
946 _e_winlist_client_replace(ec, e_client_stack_active_adjust(ec));
947 goto done;
948 }
949 }
950 if (_e_winlist_client_add(ec, _winlist_zone,
951 e_desk_current_get(_winlist_zone)))
952 _e_winlist_size_adjust();
953 done:
954 return ECORE_CALLBACK_PASS_ON;
955 }
956
957 static Eina_Bool
_e_winlist_cb_event_border_remove(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)958 _e_winlist_cb_event_border_remove(void *data EINA_UNUSED, int type EINA_UNUSED,
959 void *event)
960 {
961 E_Event_Client *ev = event;
962 E_Client *ec = ev->ec;
963
964 if (!ec->stack.prev) _e_winlist_client_del(ec);
965 else _e_winlist_client_replace(ec, e_client_stack_active_adjust(ec));
966 _e_winlist_size_adjust();
967 return ECORE_CALLBACK_PASS_ON;
968 }
969
970 static Eina_Bool
_e_winlist_cb_key_down(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)971 _e_winlist_cb_key_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
972 {
973 Ecore_Event_Key *ev = event;
974 E_Util_Action act;
975 int x = 0, y = 0;
976
977 if (ev->window != _input_window) return ECORE_CALLBACK_PASS_ON;
978 act = e_util_key_geometry_action_get(ev->key, &x, &y, 1, 1);
979 if (act == E_UTIL_ACTION_DONE)
980 e_winlist_hide();
981 else if (act == E_UTIL_ACTION_ABORT)
982 _e_winlist_restore_desktop();
983 else if (act == E_UTIL_ACTION_DO)
984 {
985 if (y < 0)
986 e_winlist_direction_select(_winlist_zone, 0);
987 else if (y > 0)
988 e_winlist_direction_select(_winlist_zone, 1);
989 else if (x < 0)
990 e_winlist_direction_select(_winlist_zone, 2);
991 else if (x > 0)
992 e_winlist_direction_select(_winlist_zone, 3);
993 }
994 else if (!strcmp(ev->key, "1"))
995 _e_winlist_activate_nth(0);
996 else if (!strcmp(ev->key, "2"))
997 _e_winlist_activate_nth(1);
998 else if (!strcmp(ev->key, "3"))
999 _e_winlist_activate_nth(2);
1000 else if (!strcmp(ev->key, "4"))
1001 _e_winlist_activate_nth(3);
1002 else if (!strcmp(ev->key, "5"))
1003 _e_winlist_activate_nth(4);
1004 else if (!strcmp(ev->key, "6"))
1005 _e_winlist_activate_nth(5);
1006 else if (!strcmp(ev->key, "7"))
1007 _e_winlist_activate_nth(6);
1008 else if (!strcmp(ev->key, "8"))
1009 _e_winlist_activate_nth(7);
1010 else if (!strcmp(ev->key, "9"))
1011 _e_winlist_activate_nth(8);
1012 else if (!strcmp(ev->key, "0"))
1013 _e_winlist_activate_nth(9);
1014 else
1015 {
1016 Eina_List *l;
1017 E_Config_Binding_Key *binding;
1018 E_Binding_Modifier mod;
1019
1020 EINA_LIST_FOREACH(e_bindings->key_bindings, l, binding)
1021 {
1022 if (binding->action != _winlist_act) continue;
1023
1024 mod = 0;
1025
1026 if (ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT)
1027 mod |= E_BINDING_MODIFIER_SHIFT;
1028 if (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL)
1029 mod |= E_BINDING_MODIFIER_CTRL;
1030 if (ev->modifiers & ECORE_EVENT_MODIFIER_ALT)
1031 mod |= E_BINDING_MODIFIER_ALT;
1032 if (ev->modifiers & ECORE_EVENT_MODIFIER_WIN)
1033 mod |= E_BINDING_MODIFIER_WIN;
1034
1035 if (binding->key && ((!strcmp(binding->key, ev->key)) || (!strcmp(binding->key, ev->keyname))) &&
1036 ((binding->modifiers == mod) || (binding->any_mod)))
1037 {
1038 if (!_act_winlist) continue;
1039 if (_act_winlist->func.go_key)
1040 _act_winlist->func.go_key(E_OBJECT(_winlist_zone), binding->params, ev);
1041 else if (_act_winlist->func.go)
1042 _act_winlist->func.go(E_OBJECT(_winlist_zone), binding->params);
1043 }
1044 }
1045 }
1046 return ECORE_CALLBACK_PASS_ON;
1047 }
1048
1049 static Eina_Bool
_e_winlist_cb_key_up(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)1050 _e_winlist_cb_key_up(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
1051 {
1052 Ecore_Event_Key *ev;
1053 Eina_List *l;
1054 E_Config_Binding_Key *binding;
1055 E_Binding_Modifier mod;
1056
1057 ev = event;
1058 if (ev->window != _input_window) return ECORE_CALLBACK_PASS_ON;
1059 if (!_winlist) return ECORE_CALLBACK_PASS_ON;
1060 if (_hold_mod)
1061 {
1062 #define KEY_CHECK(MOD, NAME) \
1063 if ((_hold_mod & ECORE_EVENT_MODIFIER_##MOD) && (!strcmp(ev->key, NAME))) \
1064 _hold_count--, _hold_mod &= ~ECORE_EVENT_MODIFIER_##MOD
1065 KEY_CHECK(SHIFT, "Shift_L");
1066 else KEY_CHECK(SHIFT, "Shift_R");
1067 else KEY_CHECK(CTRL, "Control_L");
1068 else KEY_CHECK(CTRL, "Control_R");
1069 else KEY_CHECK(ALT, "Alt_L");
1070 else KEY_CHECK(ALT, "Alt_R");
1071 else KEY_CHECK(ALT, "Meta_L");
1072 else KEY_CHECK(ALT, "Meta_R");
1073 else KEY_CHECK(WIN, "Meta_L");
1074 else KEY_CHECK(WIN, "Meta_R");
1075 else KEY_CHECK(ALT, "Super_L");
1076 else KEY_CHECK(ALT, "Super_R");
1077 else KEY_CHECK(WIN, "Super_L");
1078 else KEY_CHECK(WIN, "Super_R");
1079 else KEY_CHECK(WIN, "Mode_switch");
1080
1081 if ((_hold_count <= 0) || ((!_hold_mod) && (_activate_type == E_WINLIST_ACTIVATE_TYPE_KEY)))
1082 {
1083 e_winlist_hide();
1084 return 1;
1085 }
1086 }
1087
1088 EINA_LIST_FOREACH(e_bindings->key_bindings, l, binding)
1089 {
1090 if (binding->action != _winlist_act) continue;
1091 mod = 0;
1092
1093 if (ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT)
1094 mod |= E_BINDING_MODIFIER_SHIFT;
1095 if (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL)
1096 mod |= E_BINDING_MODIFIER_CTRL;
1097 if (ev->modifiers & ECORE_EVENT_MODIFIER_ALT)
1098 mod |= E_BINDING_MODIFIER_ALT;
1099 if (ev->modifiers & ECORE_EVENT_MODIFIER_WIN)
1100 mod |= E_BINDING_MODIFIER_WIN;
1101
1102 if (binding->key && (!strcmp(binding->key, ev->key)) &&
1103 ((binding->modifiers == mod) || (binding->any_mod)))
1104 {
1105 if (!_act_winlist) continue;
1106 if (_act_winlist->func.end_key)
1107 _act_winlist->func.end_key(E_OBJECT(_winlist_zone), binding->params, ev);
1108 else if (_act_winlist->func.end)
1109 _act_winlist->func.end(E_OBJECT(_winlist_zone), binding->params);
1110 }
1111 }
1112
1113 return ECORE_CALLBACK_PASS_ON;
1114 }
1115
1116 static Eina_Bool
_e_winlist_cb_mouse_down(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)1117 _e_winlist_cb_mouse_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
1118 {
1119 Ecore_Event_Mouse_Button *ev;
1120
1121 ev = event;
1122 if (ev->window != _input_window) return ECORE_CALLBACK_PASS_ON;
1123 e_bindings_mouse_down_ecore_event_handle(E_BINDING_CONTEXT_WINLIST,
1124 E_OBJECT(_winlist_zone), ev);
1125 return ECORE_CALLBACK_PASS_ON;
1126 }
1127
1128 static Eina_Bool
_e_winlist_cb_mouse_up(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)1129 _e_winlist_cb_mouse_up(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
1130 {
1131 Ecore_Event_Mouse_Button *ev;
1132
1133 ev = event;
1134 if (ev->window != _input_window) return ECORE_CALLBACK_PASS_ON;
1135 if (e_bindings_mouse_up_ecore_event_handle(E_BINDING_CONTEXT_WINLIST, E_OBJECT(_winlist_zone), ev))
1136 return ECORE_CALLBACK_RENEW;
1137 if (_activate_type != E_WINLIST_ACTIVATE_TYPE_MOUSE) return ECORE_CALLBACK_RENEW;
1138 if (!--_hold_count) e_winlist_hide();
1139 return ECORE_CALLBACK_PASS_ON;
1140 }
1141
1142 static Eina_Bool
_e_winlist_cb_mouse_wheel(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)1143 _e_winlist_cb_mouse_wheel(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
1144 {
1145 Ecore_Event_Mouse_Wheel *ev;
1146 int i;
1147
1148 ev = event;
1149 if (ev->window != _input_window) return ECORE_CALLBACK_PASS_ON;
1150 e_bindings_wheel_ecore_event_handle(E_BINDING_CONTEXT_WINLIST,
1151 E_OBJECT(_winlist_zone), ev);
1152 if (ev->z < 0) /* up */
1153 {
1154 for (i = ev->z; i < 0; i++)
1155 e_winlist_prev();
1156 }
1157 else if (ev->z > 0) /* down */
1158 {
1159 for (i = ev->z; i > 0; i--)
1160 e_winlist_next();
1161 }
1162 return ECORE_CALLBACK_PASS_ON;
1163 }
1164
1165 static Eina_Bool
_e_winlist_cb_mouse_move(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)1166 _e_winlist_cb_mouse_move(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
1167 {
1168 Ecore_Event_Mouse_Move *ev;
1169 int x, y, w, h;
1170
1171 ev = event;
1172 if (ev->window != _input_window) return ECORE_CALLBACK_PASS_ON;
1173 evas_object_geometry_get(_winlist, &x, &y, &w, &h);
1174 /* only feed mouse move if it's within the winlist popup */
1175 if (E_INSIDE(ev->x, ev->y, x, y, w, h))
1176 evas_event_feed_mouse_move(evas_object_evas_get(_winlist), ev->x, ev->y, ev->timestamp, NULL);
1177
1178 return ECORE_CALLBACK_PASS_ON;
1179 }
1180
1181 static Eina_Bool
_e_winlist_scroll_timer(void * data EINA_UNUSED)1182 _e_winlist_scroll_timer(void *data EINA_UNUSED)
1183 {
1184 if (_scroll_to)
1185 {
1186 double spd;
1187
1188 spd = e_config->winlist_scroll_speed;
1189 _scroll_align = (_scroll_align * (1.0 - spd)) +
1190 (_scroll_align_to * spd);
1191 return 1;
1192 }
1193 _scroll_timer = NULL;
1194 return ECORE_CALLBACK_CANCEL;
1195 }
1196
1197 static Eina_Bool
_e_winlist_animator(void * data EINA_UNUSED)1198 _e_winlist_animator(void *data EINA_UNUSED)
1199 {
1200 if (_scroll_to)
1201 {
1202 double da;
1203
1204 da = _scroll_align - _scroll_align_to;
1205 if (da < 0.0) da = -da;
1206 if (da < 0.01)
1207 {
1208 _scroll_align = _scroll_align_to;
1209 _scroll_to = 0;
1210 }
1211 elm_box_align_set(_list_object, 0.5, fabs(1.0 - _scroll_align));
1212 }
1213 if (!_scroll_to) _animator = NULL;
1214 return _scroll_to;
1215 }
1216
1217 #if 0
1218 static void
1219 _e_winlist_cb_item_mouse_in(void *data, Evas *evas, Evas_Object *obj, void *event_info)
1220 {
1221 E_Winlist_Win *ww;
1222 E_Winlist_Win *lww;
1223 Eina_List *l;
1224
1225 if (!(ww = data)) return;
1226 if (!_wins) return;
1227 EINA_LIST_FOREACH(_wins, l, lww)
1228 if (lww == ww) break;
1229 _e_winlist_deactivate();
1230 _win_selected = l;
1231 _e_winlist_show_active();
1232 _e_winlist_activate();
1233 }
1234
1235 #endif
1236