1/* swc: input.c
2 *
3 * Copyright (c) 2013, 2014 Michael Forney
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#include "input.h"
25#include "compositor.h"
26#include "event.h"
27#include "surface.h"
28#include "util.h"
29
30static void
31focus(struct input_focus *input_focus, struct compositor_view *view)
32{
33 struct wl_client *client = NULL;
34 struct wl_resource *resource, *tmp;
35
36 if (view) {
37 client = wl_resource_get_client(view->surface->resource);
38 wl_resource_for_each_safe(resource, tmp, &input_focus->inactive)
39 {
40 if (wl_resource_get_client(resource) == client) {
41 wl_list_remove(wl_resource_get_link(resource));
42 wl_list_insert(&input_focus->active,
43 wl_resource_get_link(resource));
44 }
45 }
46 wl_signal_add(&view->destroy_signal,
47 &input_focus->view_destroy_listener);
48 }
49
50 input_focus->client = client;
51 input_focus->view = view;
52 input_focus->handler->enter(input_focus->handler, &input_focus->active,
53 view);
54}
55
56static void
57unfocus(struct input_focus *input_focus)
58{
59 if (input_focus->view) {
60 wl_list_remove(&input_focus->view_destroy_listener.link);
61 }
62 input_focus->handler->leave(input_focus->handler, &input_focus->active,
63 input_focus->view);
64 wl_list_insert_list(&input_focus->inactive, &input_focus->active);
65 wl_list_init(&input_focus->active);
66}
67
68static void
69handle_focus_view_destroy(struct wl_listener *listener, void *data)
70{
71 struct input_focus *input_focus =
72 wl_container_of(listener, input_focus, view_destroy_listener);
73 struct compositor_view *view = input_focus->view;
74
75 (void)data;
76
77 /* send the leave event */
78 if (view) {
79 unfocus(input_focus);
80 }
81
82 input_focus->client = NULL;
83 input_focus->view = NULL;
84}
85
86bool
87input_focus_initialize(struct input_focus *input_focus,
88 struct input_focus_handler *handler)
89{
90 input_focus->client = NULL;
91 input_focus->view = NULL;
92 input_focus->view_destroy_listener.notify = &handle_focus_view_destroy;
93 input_focus->handler = handler;
94
95 wl_list_init(&input_focus->active);
96 wl_list_init(&input_focus->inactive);
97 wl_signal_init(&input_focus->event_signal);
98
99 return true;
100}
101
102void
103input_focus_finalize(struct input_focus *input_focus)
104{
105 /* XXX: Destroy resources? */
106}
107
108void
109input_focus_add_resource(struct input_focus *input_focus,
110 struct wl_resource *resource)
111{
112 struct wl_list resources, *target = &input_focus->inactive;
113
114 wl_list_init(&resources);
115 wl_list_insert(&resources, wl_resource_get_link(resource));
116
117 /* If this new input resource corresponds to the focused client, send an
118 * enter event. */
119 if (wl_resource_get_client(resource) == input_focus->client) {
120 input_focus->handler->enter(input_focus->handler, &resources,
121 input_focus->view);
122 target = &input_focus->active;
123 }
124
125 wl_list_insert_list(target, &resources);
126}
127
128void
129input_focus_remove_resource(struct input_focus *input_focus,
130 struct wl_resource *resource)
131{
132 wl_list_remove(wl_resource_get_link(resource));
133}
134
135void
136input_focus_set(struct input_focus *input_focus, struct compositor_view *view)
137{
138 struct input_focus_event_data data;
139
140 if (view == input_focus->view) {
141 return;
142 }
143
144 data.old = input_focus->view;
145 data.new = view;
146
147 unfocus(input_focus);
148 focus(input_focus, view);
149
150 send_event(&input_focus->event_signal, INPUT_FOCUS_EVENT_CHANGED, &data);
151}