mirror of
				https://github.com/labwc/labwc.git
				synced 2025-11-03 09:01:51 -05:00 
			
		
		
		
	Move more functions from main.c to other files
This commit is contained in:
		
							parent
							
								
									52f81e4a39
								
							
						
					
					
						commit
						3ed8e273a9
					
				
					 4 changed files with 232 additions and 221 deletions
				
			
		
							
								
								
									
										7
									
								
								labwc.h
									
										
									
									
									
								
							
							
						
						
									
										7
									
								
								labwc.h
									
										
									
									
									
								
							| 
						 | 
					@ -138,10 +138,17 @@ void focus_view(struct tinywl_view *view, struct wlr_surface *surface);
 | 
				
			||||||
void view_focus_next_toplevel(struct tinywl_server *server);
 | 
					void view_focus_next_toplevel(struct tinywl_server *server);
 | 
				
			||||||
void begin_interactive(struct tinywl_view *view, enum tinywl_cursor_mode mode, uint32_t edges);
 | 
					void begin_interactive(struct tinywl_view *view, enum tinywl_cursor_mode mode, uint32_t edges);
 | 
				
			||||||
bool is_toplevel(struct tinywl_view *view);
 | 
					bool is_toplevel(struct tinywl_view *view);
 | 
				
			||||||
 | 
					struct tinywl_view *desktop_view_at(struct tinywl_server *server, double lx, double ly,
 | 
				
			||||||
 | 
							struct wlr_surface **surface, double *sx, double *sy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* TODO: try to refactor to remove from header file */
 | 
					/* TODO: try to refactor to remove from header file */
 | 
				
			||||||
struct tinywl_view *first_toplevel(struct tinywl_server *server);
 | 
					struct tinywl_view *first_toplevel(struct tinywl_server *server);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void server_cursor_motion(struct wl_listener *listener, void *data);
 | 
				
			||||||
 | 
					void server_cursor_motion_absolute(struct wl_listener *listener, void *data);
 | 
				
			||||||
 | 
					void server_cursor_button(struct wl_listener *listener, void *data);
 | 
				
			||||||
 | 
					void server_cursor_axis(struct wl_listener *listener, void *data);
 | 
				
			||||||
 | 
					void server_cursor_frame(struct wl_listener *listener, void *data);
 | 
				
			||||||
void server_new_output(struct wl_listener *listener, void *data);
 | 
					void server_new_output(struct wl_listener *listener, void *data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void output_frame(struct wl_listener *listener, void *data);
 | 
					void output_frame(struct wl_listener *listener, void *data);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										221
									
								
								main.c
									
										
									
									
									
								
							
							
						
						
									
										221
									
								
								main.c
									
										
									
									
									
								
							| 
						 | 
					@ -273,227 +273,6 @@ static void seat_request_cursor(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool view_at(struct tinywl_view *view,
 | 
					 | 
				
			||||||
		double lx, double ly, struct wlr_surface **surface,
 | 
					 | 
				
			||||||
		double *sx, double *sy) {
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * XDG toplevels may have nested surfaces, such as popup windows for context
 | 
					 | 
				
			||||||
	 * menus or tooltips. This function tests if any of those are underneath the
 | 
					 | 
				
			||||||
	 * coordinates lx and ly (in output Layout Coordinates). If so, it sets the
 | 
					 | 
				
			||||||
	 * surface pointer to that wlr_surface and the sx and sy coordinates to the
 | 
					 | 
				
			||||||
	 * coordinates relative to that surface's top-left corner.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	double view_sx = lx - view->x;
 | 
					 | 
				
			||||||
	double view_sy = ly - view->y;
 | 
					 | 
				
			||||||
	double _sx, _sy;
 | 
					 | 
				
			||||||
	struct wlr_surface *_surface = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (view->type) {
 | 
					 | 
				
			||||||
	case LAB_XDG_SHELL_VIEW:
 | 
					 | 
				
			||||||
		_surface = wlr_xdg_surface_surface_at(
 | 
					 | 
				
			||||||
			view->xdg_surface, view_sx, view_sy, &_sx, &_sy);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case LAB_XWAYLAND_VIEW:
 | 
					 | 
				
			||||||
		if (!view->xwayland_surface->surface)
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
		_surface = wlr_surface_surface_at(
 | 
					 | 
				
			||||||
			view->xwayland_surface->surface,
 | 
					 | 
				
			||||||
			view_sx, view_sy, &_sx, &_sy);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (_surface != NULL) {
 | 
					 | 
				
			||||||
		*sx = _sx;
 | 
					 | 
				
			||||||
		*sy = _sy;
 | 
					 | 
				
			||||||
		*surface = _surface;
 | 
					 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct tinywl_view *desktop_view_at(
 | 
					 | 
				
			||||||
		struct tinywl_server *server, double lx, double ly,
 | 
					 | 
				
			||||||
		struct wlr_surface **surface, double *sx, double *sy) {
 | 
					 | 
				
			||||||
	/* This iterates over all of our surfaces and attempts to find one under the
 | 
					 | 
				
			||||||
	 * cursor. This relies on server->views being ordered from top-to-bottom. */
 | 
					 | 
				
			||||||
	struct tinywl_view *view;
 | 
					 | 
				
			||||||
	wl_list_for_each(view, &server->views, link) {
 | 
					 | 
				
			||||||
		if (view_at(view, lx, ly, surface, sx, sy)) {
 | 
					 | 
				
			||||||
			return view;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void process_cursor_move(struct tinywl_server *server, uint32_t time) {
 | 
					 | 
				
			||||||
	/* Move the grabbed view to the new position. */
 | 
					 | 
				
			||||||
	server->grabbed_view->x = server->cursor->x - server->grab_x;
 | 
					 | 
				
			||||||
	server->grabbed_view->y = server->cursor->y - server->grab_y;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void process_cursor_resize(struct tinywl_server *server, uint32_t time) {
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * Resizing the grabbed view can be a little bit complicated, because we
 | 
					 | 
				
			||||||
	 * could be resizing from any corner or edge. This not only resizes the view
 | 
					 | 
				
			||||||
	 * on one or two axes, but can also move the view if you resize from the top
 | 
					 | 
				
			||||||
	 * or left edges (or top-left corner).
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * Note that I took some shortcuts here. In a more fleshed-out compositor,
 | 
					 | 
				
			||||||
	 * you'd wait for the client to prepare a buffer at the new size, then
 | 
					 | 
				
			||||||
	 * commit any movement that was prepared.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	struct tinywl_view *view = server->grabbed_view;
 | 
					 | 
				
			||||||
	double dx = server->cursor->x - server->grab_x;
 | 
					 | 
				
			||||||
	double dy = server->cursor->y - server->grab_y;
 | 
					 | 
				
			||||||
	double x = view->x;
 | 
					 | 
				
			||||||
	double y = view->y;
 | 
					 | 
				
			||||||
	int width = server->grab_width;
 | 
					 | 
				
			||||||
	int height = server->grab_height;
 | 
					 | 
				
			||||||
	if (server->resize_edges & WLR_EDGE_TOP) {
 | 
					 | 
				
			||||||
		y = server->grab_y + dy;
 | 
					 | 
				
			||||||
		height -= dy;
 | 
					 | 
				
			||||||
		if (height < 1) {
 | 
					 | 
				
			||||||
			y += height;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else if (server->resize_edges & WLR_EDGE_BOTTOM) {
 | 
					 | 
				
			||||||
		height += dy;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (server->resize_edges & WLR_EDGE_LEFT) {
 | 
					 | 
				
			||||||
		x = server->grab_x + dx;
 | 
					 | 
				
			||||||
		width -= dx;
 | 
					 | 
				
			||||||
		if (width < 1) {
 | 
					 | 
				
			||||||
			x += width;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else if (server->resize_edges & WLR_EDGE_RIGHT) {
 | 
					 | 
				
			||||||
		width += dx;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	view->x = x;
 | 
					 | 
				
			||||||
	view->y = y;
 | 
					 | 
				
			||||||
	wlr_xdg_toplevel_set_size(view->xdg_surface, width, height);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void process_cursor_motion(struct tinywl_server *server, uint32_t time) {
 | 
					 | 
				
			||||||
	/* If the mode is non-passthrough, delegate to those functions. */
 | 
					 | 
				
			||||||
	if (server->cursor_mode == TINYWL_CURSOR_MOVE) {
 | 
					 | 
				
			||||||
		process_cursor_move(server, time);
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	} else if (server->cursor_mode == TINYWL_CURSOR_RESIZE) {
 | 
					 | 
				
			||||||
		process_cursor_resize(server, time);
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Otherwise, find the view under the pointer and send the event along. */
 | 
					 | 
				
			||||||
	double sx, sy;
 | 
					 | 
				
			||||||
	struct wlr_seat *seat = server->seat;
 | 
					 | 
				
			||||||
	struct wlr_surface *surface = NULL;
 | 
					 | 
				
			||||||
	struct tinywl_view *view = desktop_view_at(server,
 | 
					 | 
				
			||||||
			server->cursor->x, server->cursor->y, &surface, &sx, &sy);
 | 
					 | 
				
			||||||
	if (!view) {
 | 
					 | 
				
			||||||
		/* If there's no view under the cursor, set the cursor image to a
 | 
					 | 
				
			||||||
		 * default. This is what makes the cursor image appear when you move it
 | 
					 | 
				
			||||||
		 * around the screen, not over any views. */
 | 
					 | 
				
			||||||
		wlr_xcursor_manager_set_cursor_image(
 | 
					 | 
				
			||||||
				server->cursor_mgr, "left_ptr", server->cursor);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (surface) {
 | 
					 | 
				
			||||||
		bool focus_changed = seat->pointer_state.focused_surface != surface;
 | 
					 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * "Enter" the surface if necessary. This lets the client know that the
 | 
					 | 
				
			||||||
		 * cursor has entered one of its surfaces.
 | 
					 | 
				
			||||||
		 *
 | 
					 | 
				
			||||||
		 * Note that this gives the surface "pointer focus", which is distinct
 | 
					 | 
				
			||||||
		 * from keyboard focus. You get pointer focus by moving the pointer over
 | 
					 | 
				
			||||||
		 * a window.
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
 | 
					 | 
				
			||||||
		if (!focus_changed) {
 | 
					 | 
				
			||||||
			/* The enter event contains coordinates, so we only need to notify
 | 
					 | 
				
			||||||
			 * on motion if the focus did not change. */
 | 
					 | 
				
			||||||
			wlr_seat_pointer_notify_motion(seat, time, sx, sy);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		/* Clear pointer focus so future button events and such are not sent to
 | 
					 | 
				
			||||||
		 * the last client to have the cursor over it. */
 | 
					 | 
				
			||||||
		wlr_seat_pointer_clear_focus(seat);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void server_cursor_motion(struct wl_listener *listener, void *data) {
 | 
					 | 
				
			||||||
	/* This event is forwarded by the cursor when a pointer emits a _relative_
 | 
					 | 
				
			||||||
	 * pointer motion event (i.e. a delta) */
 | 
					 | 
				
			||||||
	struct tinywl_server *server =
 | 
					 | 
				
			||||||
		wl_container_of(listener, server, cursor_motion);
 | 
					 | 
				
			||||||
	struct wlr_event_pointer_motion *event = data;
 | 
					 | 
				
			||||||
	/* The cursor doesn't move unless we tell it to. The cursor automatically
 | 
					 | 
				
			||||||
	 * handles constraining the motion to the output layout, as well as any
 | 
					 | 
				
			||||||
	 * special configuration applied for the specific input device which
 | 
					 | 
				
			||||||
	 * generated the event. You can pass NULL for the device if you want to move
 | 
					 | 
				
			||||||
	 * the cursor around without any input. */
 | 
					 | 
				
			||||||
	wlr_cursor_move(server->cursor, event->device,
 | 
					 | 
				
			||||||
			event->delta_x, event->delta_y);
 | 
					 | 
				
			||||||
	process_cursor_motion(server, event->time_msec);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void server_cursor_motion_absolute(
 | 
					 | 
				
			||||||
		struct wl_listener *listener, void *data) {
 | 
					 | 
				
			||||||
	/* This event is forwarded by the cursor when a pointer emits an _absolute_
 | 
					 | 
				
			||||||
	 * motion event, from 0..1 on each axis. This happens, for example, when
 | 
					 | 
				
			||||||
	 * wlroots is running under a Wayland window rather than KMS+DRM, and you
 | 
					 | 
				
			||||||
	 * move the mouse over the window. You could enter the window from any edge,
 | 
					 | 
				
			||||||
	 * so we have to warp the mouse there. There is also some hardware which
 | 
					 | 
				
			||||||
	 * emits these events. */
 | 
					 | 
				
			||||||
	struct tinywl_server *server =
 | 
					 | 
				
			||||||
		wl_container_of(listener, server, cursor_motion_absolute);
 | 
					 | 
				
			||||||
	struct wlr_event_pointer_motion_absolute *event = data;
 | 
					 | 
				
			||||||
	wlr_cursor_warp_absolute(server->cursor, event->device, event->x, event->y);
 | 
					 | 
				
			||||||
	process_cursor_motion(server, event->time_msec);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void server_cursor_button(struct wl_listener *listener, void *data) {
 | 
					 | 
				
			||||||
	/* This event is forwarded by the cursor when a pointer emits a button
 | 
					 | 
				
			||||||
	 * event. */
 | 
					 | 
				
			||||||
	struct tinywl_server *server =
 | 
					 | 
				
			||||||
		wl_container_of(listener, server, cursor_button);
 | 
					 | 
				
			||||||
	struct wlr_event_pointer_button *event = data;
 | 
					 | 
				
			||||||
	/* Notify the client with pointer focus that a button press has occurred */
 | 
					 | 
				
			||||||
	wlr_seat_pointer_notify_button(server->seat,
 | 
					 | 
				
			||||||
			event->time_msec, event->button, event->state);
 | 
					 | 
				
			||||||
	double sx, sy;
 | 
					 | 
				
			||||||
	struct wlr_surface *surface;
 | 
					 | 
				
			||||||
	struct tinywl_view *view = desktop_view_at(server,
 | 
					 | 
				
			||||||
			server->cursor->x, server->cursor->y, &surface, &sx, &sy);
 | 
					 | 
				
			||||||
	if (event->state == WLR_BUTTON_RELEASED) {
 | 
					 | 
				
			||||||
		/* If you released any buttons, we exit interactive move/resize mode. */
 | 
					 | 
				
			||||||
		server->cursor_mode = TINYWL_CURSOR_PASSTHROUGH;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		/* Focus that client if the button was _pressed_ */
 | 
					 | 
				
			||||||
		focus_view(view, surface);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void server_cursor_axis(struct wl_listener *listener, void *data) {
 | 
					 | 
				
			||||||
	/* This event is forwarded by the cursor when a pointer emits an axis event,
 | 
					 | 
				
			||||||
	 * for example when you move the scroll wheel. */
 | 
					 | 
				
			||||||
	struct tinywl_server *server =
 | 
					 | 
				
			||||||
		wl_container_of(listener, server, cursor_axis);
 | 
					 | 
				
			||||||
	struct wlr_event_pointer_axis *event = data;
 | 
					 | 
				
			||||||
	/* Notify the client with pointer focus of the axis event. */
 | 
					 | 
				
			||||||
	wlr_seat_pointer_notify_axis(server->seat,
 | 
					 | 
				
			||||||
			event->time_msec, event->orientation, event->delta,
 | 
					 | 
				
			||||||
			event->delta_discrete, event->source);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void server_cursor_frame(struct wl_listener *listener, void *data) {
 | 
					 | 
				
			||||||
	/* This event is forwarded by the cursor when a pointer emits an frame
 | 
					 | 
				
			||||||
	 * event. Frame events are sent after regular pointer events to group
 | 
					 | 
				
			||||||
	 * multiple events together. For instance, two axis events may happen at the
 | 
					 | 
				
			||||||
	 * same time, in which case a frame event won't be sent in between. */
 | 
					 | 
				
			||||||
	struct tinywl_server *server =
 | 
					 | 
				
			||||||
		wl_container_of(listener, server, cursor_frame);
 | 
					 | 
				
			||||||
	/* Notify the client with pointer focus of the frame event. */
 | 
					 | 
				
			||||||
	wlr_seat_pointer_notify_frame(server->seat);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main(int argc, char *argv[]) {
 | 
					int main(int argc, char *argv[]) {
 | 
				
			||||||
	wlr_log_init(WLR_ERROR, NULL);
 | 
						wlr_log_init(WLR_ERROR, NULL);
 | 
				
			||||||
	char *startup_cmd = NULL;
 | 
						char *startup_cmd = NULL;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										174
									
								
								server.c
									
										
									
									
									
								
							
							
						
						
									
										174
									
								
								server.c
									
										
									
									
									
								
							| 
						 | 
					@ -1,5 +1,179 @@
 | 
				
			||||||
#include "labwc.h"
 | 
					#include "labwc.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void process_cursor_move(struct tinywl_server *server, uint32_t time)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* Move the grabbed view to the new position. */
 | 
				
			||||||
 | 
						server->grabbed_view->x = server->cursor->x - server->grab_x;
 | 
				
			||||||
 | 
						server->grabbed_view->y = server->cursor->y - server->grab_y;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void process_cursor_resize(struct tinywl_server *server, uint32_t time)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Resizing the grabbed view can be a little bit complicated, because we
 | 
				
			||||||
 | 
						 * could be resizing from any corner or edge. This not only resizes the view
 | 
				
			||||||
 | 
						 * on one or two axes, but can also move the view if you resize from the top
 | 
				
			||||||
 | 
						 * or left edges (or top-left corner).
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Note that I took some shortcuts here. In a more fleshed-out compositor,
 | 
				
			||||||
 | 
						 * you'd wait for the client to prepare a buffer at the new size, then
 | 
				
			||||||
 | 
						 * commit any movement that was prepared.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						struct tinywl_view *view = server->grabbed_view;
 | 
				
			||||||
 | 
						double dx = server->cursor->x - server->grab_x;
 | 
				
			||||||
 | 
						double dy = server->cursor->y - server->grab_y;
 | 
				
			||||||
 | 
						double x = view->x;
 | 
				
			||||||
 | 
						double y = view->y;
 | 
				
			||||||
 | 
						int width = server->grab_width;
 | 
				
			||||||
 | 
						int height = server->grab_height;
 | 
				
			||||||
 | 
						if (server->resize_edges & WLR_EDGE_TOP) {
 | 
				
			||||||
 | 
							y = server->grab_y + dy;
 | 
				
			||||||
 | 
							height -= dy;
 | 
				
			||||||
 | 
							if (height < 1) {
 | 
				
			||||||
 | 
								y += height;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else if (server->resize_edges & WLR_EDGE_BOTTOM) {
 | 
				
			||||||
 | 
							height += dy;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (server->resize_edges & WLR_EDGE_LEFT) {
 | 
				
			||||||
 | 
							x = server->grab_x + dx;
 | 
				
			||||||
 | 
							width -= dx;
 | 
				
			||||||
 | 
							if (width < 1) {
 | 
				
			||||||
 | 
								x += width;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else if (server->resize_edges & WLR_EDGE_RIGHT) {
 | 
				
			||||||
 | 
							width += dx;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						view->x = x;
 | 
				
			||||||
 | 
						view->y = y;
 | 
				
			||||||
 | 
						wlr_xdg_toplevel_set_size(view->xdg_surface, width, height);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void process_cursor_motion(struct tinywl_server *server, uint32_t time)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* If the mode is non-passthrough, delegate to those functions. */
 | 
				
			||||||
 | 
						if (server->cursor_mode == TINYWL_CURSOR_MOVE) {
 | 
				
			||||||
 | 
							process_cursor_move(server, time);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						} else if (server->cursor_mode == TINYWL_CURSOR_RESIZE) {
 | 
				
			||||||
 | 
							process_cursor_resize(server, time);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Otherwise, find the view under the pointer and send the event along. */
 | 
				
			||||||
 | 
						double sx, sy;
 | 
				
			||||||
 | 
						struct wlr_seat *seat = server->seat;
 | 
				
			||||||
 | 
						struct wlr_surface *surface = NULL;
 | 
				
			||||||
 | 
						struct tinywl_view *view = desktop_view_at(server,
 | 
				
			||||||
 | 
								server->cursor->x, server->cursor->y, &surface, &sx, &sy);
 | 
				
			||||||
 | 
						if (!view) {
 | 
				
			||||||
 | 
							/* If there's no view under the cursor, set the cursor image to a
 | 
				
			||||||
 | 
							 * default. This is what makes the cursor image appear when you move it
 | 
				
			||||||
 | 
							 * around the screen, not over any views. */
 | 
				
			||||||
 | 
							wlr_xcursor_manager_set_cursor_image(
 | 
				
			||||||
 | 
									server->cursor_mgr, "left_ptr", server->cursor);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (surface) {
 | 
				
			||||||
 | 
							bool focus_changed = seat->pointer_state.focused_surface != surface;
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * "Enter" the surface if necessary. This lets the client know that the
 | 
				
			||||||
 | 
							 * cursor has entered one of its surfaces.
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
 | 
							 * Note that this gives the surface "pointer focus", which is distinct
 | 
				
			||||||
 | 
							 * from keyboard focus. You get pointer focus by moving the pointer over
 | 
				
			||||||
 | 
							 * a window.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
 | 
				
			||||||
 | 
							if (!focus_changed) {
 | 
				
			||||||
 | 
								/* The enter event contains coordinates, so we only need to notify
 | 
				
			||||||
 | 
								 * on motion if the focus did not change. */
 | 
				
			||||||
 | 
								wlr_seat_pointer_notify_motion(seat, time, sx, sy);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							/* Clear pointer focus so future button events and such are not sent to
 | 
				
			||||||
 | 
							 * the last client to have the cursor over it. */
 | 
				
			||||||
 | 
							wlr_seat_pointer_clear_focus(seat);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void server_cursor_motion(struct wl_listener *listener, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* This event is forwarded by the cursor when a pointer emits a _relative_
 | 
				
			||||||
 | 
						 * pointer motion event (i.e. a delta) */
 | 
				
			||||||
 | 
						struct tinywl_server *server =
 | 
				
			||||||
 | 
							wl_container_of(listener, server, cursor_motion);
 | 
				
			||||||
 | 
						struct wlr_event_pointer_motion *event = data;
 | 
				
			||||||
 | 
						/* The cursor doesn't move unless we tell it to. The cursor automatically
 | 
				
			||||||
 | 
						 * handles constraining the motion to the output layout, as well as any
 | 
				
			||||||
 | 
						 * special configuration applied for the specific input device which
 | 
				
			||||||
 | 
						 * generated the event. You can pass NULL for the device if you want to move
 | 
				
			||||||
 | 
						 * the cursor around without any input. */
 | 
				
			||||||
 | 
						wlr_cursor_move(server->cursor, event->device,
 | 
				
			||||||
 | 
								event->delta_x, event->delta_y);
 | 
				
			||||||
 | 
						process_cursor_motion(server, event->time_msec);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void server_cursor_motion_absolute(struct wl_listener *listener, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* This event is forwarded by the cursor when a pointer emits an _absolute_
 | 
				
			||||||
 | 
						 * motion event, from 0..1 on each axis. This happens, for example, when
 | 
				
			||||||
 | 
						 * wlroots is running under a Wayland window rather than KMS+DRM, and you
 | 
				
			||||||
 | 
						 * move the mouse over the window. You could enter the window from any edge,
 | 
				
			||||||
 | 
						 * so we have to warp the mouse there. There is also some hardware which
 | 
				
			||||||
 | 
						 * emits these events. */
 | 
				
			||||||
 | 
						struct tinywl_server *server =
 | 
				
			||||||
 | 
							wl_container_of(listener, server, cursor_motion_absolute);
 | 
				
			||||||
 | 
						struct wlr_event_pointer_motion_absolute *event = data;
 | 
				
			||||||
 | 
						wlr_cursor_warp_absolute(server->cursor, event->device, event->x, event->y);
 | 
				
			||||||
 | 
						process_cursor_motion(server, event->time_msec);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void server_cursor_button(struct wl_listener *listener, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* This event is forwarded by the cursor when a pointer emits a button
 | 
				
			||||||
 | 
						 * event. */
 | 
				
			||||||
 | 
						struct tinywl_server *server =
 | 
				
			||||||
 | 
							wl_container_of(listener, server, cursor_button);
 | 
				
			||||||
 | 
						struct wlr_event_pointer_button *event = data;
 | 
				
			||||||
 | 
						/* Notify the client with pointer focus that a button press has occurred */
 | 
				
			||||||
 | 
						wlr_seat_pointer_notify_button(server->seat,
 | 
				
			||||||
 | 
								event->time_msec, event->button, event->state);
 | 
				
			||||||
 | 
						double sx, sy;
 | 
				
			||||||
 | 
						struct wlr_surface *surface;
 | 
				
			||||||
 | 
						struct tinywl_view *view = desktop_view_at(server,
 | 
				
			||||||
 | 
								server->cursor->x, server->cursor->y, &surface, &sx, &sy);
 | 
				
			||||||
 | 
						if (event->state == WLR_BUTTON_RELEASED) {
 | 
				
			||||||
 | 
							/* If you released any buttons, we exit interactive move/resize mode. */
 | 
				
			||||||
 | 
							server->cursor_mode = TINYWL_CURSOR_PASSTHROUGH;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							/* Focus that client if the button was _pressed_ */
 | 
				
			||||||
 | 
							focus_view(view, surface);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void server_cursor_axis(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						/* This event is forwarded by the cursor when a pointer emits an axis event,
 | 
				
			||||||
 | 
						 * for example when you move the scroll wheel. */
 | 
				
			||||||
 | 
						struct tinywl_server *server =
 | 
				
			||||||
 | 
							wl_container_of(listener, server, cursor_axis);
 | 
				
			||||||
 | 
						struct wlr_event_pointer_axis *event = data;
 | 
				
			||||||
 | 
						/* Notify the client with pointer focus of the axis event. */
 | 
				
			||||||
 | 
						wlr_seat_pointer_notify_axis(server->seat,
 | 
				
			||||||
 | 
								event->time_msec, event->orientation, event->delta,
 | 
				
			||||||
 | 
								event->delta_discrete, event->source);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void server_cursor_frame(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						/* This event is forwarded by the cursor when a pointer emits an frame
 | 
				
			||||||
 | 
						 * event. Frame events are sent after regular pointer events to group
 | 
				
			||||||
 | 
						 * multiple events together. For instance, two axis events may happen at the
 | 
				
			||||||
 | 
						 * same time, in which case a frame event won't be sent in between. */
 | 
				
			||||||
 | 
						struct tinywl_server *server =
 | 
				
			||||||
 | 
							wl_container_of(listener, server, cursor_frame);
 | 
				
			||||||
 | 
						/* Notify the client with pointer focus of the frame event. */
 | 
				
			||||||
 | 
						wlr_seat_pointer_notify_frame(server->seat);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void server_new_output(struct wl_listener *listener, void *data)
 | 
					void server_new_output(struct wl_listener *listener, void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* This event is rasied by the backend when a new output (aka a display or
 | 
						/* This event is rasied by the backend when a new output (aka a display or
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										51
									
								
								view.c
									
										
									
									
									
								
							
							
						
						
									
										51
									
								
								view.c
									
										
									
									
									
								
							| 
						 | 
					@ -150,3 +150,54 @@ struct tinywl_view *first_toplevel(struct tinywl_server *server) {
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool view_at(struct tinywl_view *view,
 | 
				
			||||||
 | 
							double lx, double ly, struct wlr_surface **surface,
 | 
				
			||||||
 | 
							double *sx, double *sy) {
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * XDG toplevels may have nested surfaces, such as popup windows for context
 | 
				
			||||||
 | 
						 * menus or tooltips. This function tests if any of those are underneath the
 | 
				
			||||||
 | 
						 * coordinates lx and ly (in output Layout Coordinates). If so, it sets the
 | 
				
			||||||
 | 
						 * surface pointer to that wlr_surface and the sx and sy coordinates to the
 | 
				
			||||||
 | 
						 * coordinates relative to that surface's top-left corner.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						double view_sx = lx - view->x;
 | 
				
			||||||
 | 
						double view_sy = ly - view->y;
 | 
				
			||||||
 | 
						double _sx, _sy;
 | 
				
			||||||
 | 
						struct wlr_surface *_surface = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (view->type) {
 | 
				
			||||||
 | 
						case LAB_XDG_SHELL_VIEW:
 | 
				
			||||||
 | 
							_surface = wlr_xdg_surface_surface_at(
 | 
				
			||||||
 | 
								view->xdg_surface, view_sx, view_sy, &_sx, &_sy);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case LAB_XWAYLAND_VIEW:
 | 
				
			||||||
 | 
							if (!view->xwayland_surface->surface)
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							_surface = wlr_surface_surface_at(
 | 
				
			||||||
 | 
								view->xwayland_surface->surface,
 | 
				
			||||||
 | 
								view_sx, view_sy, &_sx, &_sy);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (_surface != NULL) {
 | 
				
			||||||
 | 
							*sx = _sx;
 | 
				
			||||||
 | 
							*sy = _sy;
 | 
				
			||||||
 | 
							*surface = _surface;
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct tinywl_view *desktop_view_at(struct tinywl_server *server, double lx, double ly,
 | 
				
			||||||
 | 
							struct wlr_surface **surface, double *sx, double *sy) {
 | 
				
			||||||
 | 
						/* This iterates over all of our surfaces and attempts to find one under the
 | 
				
			||||||
 | 
						 * cursor. This relies on server->views being ordered from top-to-bottom. */
 | 
				
			||||||
 | 
						struct tinywl_view *view;
 | 
				
			||||||
 | 
						wl_list_for_each(view, &server->views, link) {
 | 
				
			||||||
 | 
							if (view_at(view, lx, ly, surface, sx, sy)) {
 | 
				
			||||||
 | 
								return view;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue