main neuswc / libswc / input.c
  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}