Wayland: Add support for idle.
When the user doesn't have a seat, or their compositor doesn't support the idle protocol, we'll assume that they are not idle. Also, rename wl_output to something that doesn't exist yet.
This commit is contained in:
		
							parent
							
								
									74c5d97181
								
							
						
					
					
						commit
						859c18a2e9
					
				
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @ -141,6 +141,8 @@ wayland-protocols: src/wayland/protocols/wlr-layer-shell-unstable-v1.xml | ||||
| 	wayland-scanner private-code ${DATA_DIR_WAYLAND_PROTOCOLS}/unstable/xdg-output/xdg-output-unstable-v1.xml src/wayland/protocols/xdg-output-unstable-v1.h | ||||
| 	wayland-scanner client-header src/wayland/protocols/wlr-layer-shell-unstable-v1.xml src/wayland/protocols/wlr-layer-shell-unstable-v1-client-header.h | ||||
| 	wayland-scanner private-code src/wayland/protocols/wlr-layer-shell-unstable-v1.xml src/wayland/protocols/wlr-layer-shell-unstable-v1.h | ||||
| 	wayland-scanner client-header src/wayland/protocols/idle.xml src/wayland/protocols/idle-client-header.h | ||||
| 	wayland-scanner private-code src/wayland/protocols/idle.xml src/wayland/protocols/idle.h | ||||
| 
 | ||||
| .PHONY: clean clean-dunst clean-dunstify clean-doc clean-tests clean-coverage clean-coverage-run | ||||
| clean: clean-dunst clean-dunstify clean-doc clean-tests clean-coverage clean-coverage-run clean-wayland-protocols | ||||
|  | ||||
| @ -264,7 +264,7 @@ Set to 0 to disable. | ||||
| A client can mark a notification as transient to bypass this setting and timeout | ||||
| anyway. Use a rule with 'set_transient = no' to disable this behavior. | ||||
| 
 | ||||
| Note: this doesn't work on wayland yet. | ||||
| Note: this doesn't work on xwayland yet. | ||||
| 
 | ||||
| =item B<font> (default: "Monospace 8") | ||||
| 
 | ||||
|  | ||||
| @ -5,11 +5,16 @@ | ||||
| #include "x11/screen.h" | ||||
| #include "wayland/wl.h" | ||||
| 
 | ||||
| const bool is_running_wayland(void){ | ||||
| const bool is_running_wayland(void) { | ||||
|         char* wayland_display = getenv("WAYLAND_DISPLAY"); | ||||
|         return !(wayland_display == NULL); | ||||
| } | ||||
| 
 | ||||
| const bool is_running_xwayland(void) { | ||||
|         // FIXME
 | ||||
|         return false; | ||||
| } | ||||
| 
 | ||||
| const struct output output_x11 = { | ||||
|         x_setup, | ||||
|         x_free, | ||||
|  | ||||
| @ -144,8 +144,8 @@ static bool queues_notification_is_finished(struct notification *n, struct dunst | ||||
|         bool is_idle = status.fullscreen ? false : status.idle; | ||||
| 
 | ||||
|         /* don't timeout when user is idle */ | ||||
|         /* NOTE: Idle is not working on wayland */ | ||||
|         if (is_idle && !n->transient && !is_running_wayland()) { | ||||
|         /* NOTE: Idle is not working on xwayland */ | ||||
|         if (is_idle && !n->transient && !is_running_xwayland()) { | ||||
|                 n->start = time_monotonic_now(); | ||||
|                 return false; | ||||
|         } | ||||
|  | ||||
							
								
								
									
										49
									
								
								src/wayland/protocols/idle.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/wayland/protocols/idle.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <protocol name="idle"> | ||||
|   <copyright><![CDATA[ | ||||
|     Copyright (C) 2015 Martin Gräßlin | ||||
| 
 | ||||
|     This program is free software: you can redistribute it and/or modify | ||||
|     it under the terms of the GNU Lesser General Public License as published by | ||||
|     the Free Software Foundation, either version 2.1 of the License, or | ||||
|     (at your option) any later version. | ||||
| 
 | ||||
|     This program is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|     GNU Lesser General Public License for more details. | ||||
| 
 | ||||
|     You should have received a copy of the GNU Lesser General Public License | ||||
|     along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|   ]]></copyright> | ||||
|   <interface  name="org_kde_kwin_idle" version="1"> | ||||
|       <description summary="User idle time manager"> | ||||
|         This interface allows to monitor user idle time on a given seat. The interface | ||||
|         allows to register timers which trigger after no user activity was registered | ||||
|         on the seat for a given interval. It notifies when user activity resumes. | ||||
| 
 | ||||
|         This is useful for applications wanting to perform actions when the user is not | ||||
|         interacting with the system, e.g. chat applications setting the user as away, power | ||||
|         management features to dim screen, etc.. | ||||
|       </description> | ||||
|       <request name="get_idle_timeout"> | ||||
|         <arg name="id" type="new_id" interface="org_kde_kwin_idle_timeout"/> | ||||
|         <arg name="seat" type="object" interface="wl_seat"/> | ||||
|         <arg name="timeout" type="uint" summary="The idle timeout in msec"/> | ||||
|       </request> | ||||
|   </interface> | ||||
|   <interface name="org_kde_kwin_idle_timeout" version="1"> | ||||
|       <request name="release" type="destructor"> | ||||
|         <description summary="release the timeout object"/> | ||||
|       </request> | ||||
|       <request name="simulate_user_activity"> | ||||
|           <description summary="Simulates user activity for this timeout, behaves just like real user activity on the seat"/> | ||||
|       </request> | ||||
|       <event name="idle"> | ||||
|           <description summary="Triggered when there has not been any user activity in the requested idle time interval"/> | ||||
|       </event> | ||||
|       <event name="resumed"> | ||||
|           <description summary="Triggered on the first user activity after an idle event"/> | ||||
|       </event> | ||||
|   </interface> | ||||
| </protocol> | ||||
| @ -20,8 +20,11 @@ | ||||
| #include "protocols/xdg-shell.h" | ||||
| #include "protocols/wlr-layer-shell-unstable-v1-client-header.h" | ||||
| #include "protocols/wlr-layer-shell-unstable-v1.h" | ||||
| #include "protocols/idle-client-header.h" | ||||
| #include "protocols/idle.h" | ||||
| #include "pool-buffer.h" | ||||
| 
 | ||||
| 
 | ||||
| #include "../log.h" | ||||
| #include "../settings.h" | ||||
| #include "../queues.h" | ||||
| @ -59,8 +62,11 @@ struct wl_ctx { | ||||
|         struct zwlr_layer_surface_v1 *layer_surface; | ||||
|         struct wl_output *layer_surface_output; | ||||
|         struct wl_callback *frame_callback; | ||||
|         struct org_kde_kwin_idle *idle_handler; | ||||
|         bool configured; | ||||
|         bool dirty; | ||||
|         bool is_idle; | ||||
|         bool has_seat; | ||||
| 
 | ||||
| 	struct { | ||||
| 		struct wl_pointer *wl_pointer; | ||||
| @ -74,7 +80,7 @@ struct wl_ctx { | ||||
|         struct pool_buffer *current_buffer; | ||||
| }; | ||||
| 
 | ||||
| struct wl_output { | ||||
| struct dunst_output { | ||||
|         uint32_t global_name; | ||||
|         char *name; | ||||
|         struct wl_output *wl_output; | ||||
| @ -82,6 +88,7 @@ struct wl_output { | ||||
|         struct wl_list link; | ||||
| 
 | ||||
|         uint32_t scale; | ||||
|         uint32_t subpixel; // TODO do something with it
 | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| @ -95,7 +102,7 @@ static void noop() { | ||||
| void set_dirty(); | ||||
| static void xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output, | ||||
|                 const char *name) { | ||||
|         struct wl_output *output = data; | ||||
|         struct dunst_output *output = data; | ||||
|         output->name = g_strdup(name); | ||||
| } | ||||
| 
 | ||||
| @ -107,7 +114,7 @@ static const struct zxdg_output_v1_listener xdg_output_listener = { | ||||
|         .description = noop, | ||||
| }; | ||||
| 
 | ||||
| static void get_xdg_output(struct wl_output *output) { | ||||
| static void get_xdg_output(struct dunst_output *output) { | ||||
|         if (ctx.xdg_output_manager == NULL || | ||||
|                         output->xdg_output != NULL) { | ||||
|                 return; | ||||
| @ -124,13 +131,13 @@ static void output_handle_geometry(void *data, struct wl_output *wl_output, | ||||
|                 int32_t subpixel, const char *make, const char *model, | ||||
|                 int32_t transform) { | ||||
|         //TODO
 | ||||
|         /* struct wl_output *output = data; */ | ||||
|         /* output->subpixel = subpixel; */ | ||||
|         struct dunst_output *output = data; | ||||
|         output->subpixel = subpixel; | ||||
| } | ||||
| 
 | ||||
| static void output_handle_scale(void *data, struct wl_output *wl_output, | ||||
|                 int32_t factor) { | ||||
|         struct wl_output *output = data; | ||||
|         struct dunst_output *output = data; | ||||
|         output->scale = factor; | ||||
| } | ||||
| 
 | ||||
| @ -142,27 +149,30 @@ static const struct wl_output_listener output_listener = { | ||||
| }; | ||||
| 
 | ||||
| static void create_output( struct wl_output *wl_output, uint32_t global_name) { | ||||
|         struct wl_output *output = g_malloc0(sizeof(struct wl_output)); | ||||
|         struct dunst_output *output = g_malloc0(sizeof(struct dunst_output)); | ||||
|         if (output == NULL) { | ||||
|                 fprintf(stderr, "allocation failed\n"); | ||||
|                 return; | ||||
|         } | ||||
|         static int number = 0; | ||||
|         LOG_I("New output %i - id %i", global_name, number); | ||||
|         output->global_name = global_name; | ||||
|         output->wl_output = wl_output; | ||||
|         // TODO: Fix this
 | ||||
|         //output->scale = 1;
 | ||||
|         //wl_list_insert(&state->outputs, &output->link);
 | ||||
|         output->scale = 1; | ||||
|         wl_list_insert(&ctx.outputs, &output->link); | ||||
| 
 | ||||
|         wl_output_set_user_data(wl_output, output); | ||||
|         wl_output_add_listener(wl_output, &output_listener, output); | ||||
|         get_xdg_output(output); | ||||
|         number++; | ||||
| } | ||||
| 
 | ||||
| static void destroy_output(struct wl_output *output) { | ||||
|         if (ctx.surface_output == output) { | ||||
| static void destroy_output(struct dunst_output *output) { | ||||
|         if (ctx.surface_output == output->wl_output) { | ||||
|                 ctx.surface_output = NULL; | ||||
|         } | ||||
|         if (ctx.layer_surface_output == output) { | ||||
|         if (ctx.layer_surface_output == output->wl_output) { | ||||
|                 ctx.layer_surface_output = NULL; | ||||
|         } | ||||
|         wl_list_remove(&output->link); | ||||
| @ -336,6 +346,26 @@ static const struct zwlr_layer_surface_v1_listener layer_surface_listener = { | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| static void idle_start (void *data, struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout){ | ||||
|         ctx.is_idle = true; | ||||
|         LOG_I("User went idle"); | ||||
| } | ||||
| static void idle_stop (void *data, struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout) { | ||||
|         ctx.is_idle = false; | ||||
|         LOG_I("User isn't idle anymore"); | ||||
| } | ||||
| 
 | ||||
| static const struct org_kde_kwin_idle_timeout_listener idle_timeout_listener = { | ||||
|         .idle = idle_start, | ||||
|         .resumed = idle_stop, | ||||
| }; | ||||
| 
 | ||||
| static void add_seat_to_idle_handler(struct wl_seat *seat){ | ||||
|         uint32_t timeout_ms = settings.idle_threshold/1000; | ||||
|         struct org_kde_kwin_idle_timeout *idle_timeout = org_kde_kwin_idle_get_idle_timeout(ctx.idle_handler, ctx.seat, timeout_ms); | ||||
|         org_kde_kwin_idle_timeout_add_listener(idle_timeout, &idle_timeout_listener, 0); | ||||
| } | ||||
| 
 | ||||
| static void handle_global(void *data, struct wl_registry *registry, | ||||
|                 uint32_t name, const char *interface, uint32_t version) { | ||||
|         if (strcmp(interface, wl_compositor_interface.name) == 0) { | ||||
| @ -350,6 +380,8 @@ static void handle_global(void *data, struct wl_registry *registry, | ||||
|         } else if (strcmp(interface, wl_seat_interface.name) == 0) { | ||||
|                 ctx.seat = wl_registry_bind(registry, name, &wl_seat_interface, 3); | ||||
|                 wl_seat_add_listener(ctx.seat, &seat_listener, ctx.seat); | ||||
|                 add_seat_to_idle_handler(ctx.seat); | ||||
|                 ctx.has_seat = true; | ||||
|         } else if (strcmp(interface, wl_output_interface.name) == 0) { | ||||
|                 struct wl_output *output = | ||||
|                         wl_registry_bind(registry, name, &wl_output_interface, 3); | ||||
| @ -359,12 +391,15 @@ static void handle_global(void *data, struct wl_registry *registry, | ||||
|                 ctx.xdg_output_manager = wl_registry_bind(registry, name, | ||||
|                         &zxdg_output_manager_v1_interface, | ||||
|                         ZXDG_OUTPUT_V1_NAME_SINCE_VERSION); | ||||
|         } else if (strcmp(interface, org_kde_kwin_idle_interface.name) == 0 && | ||||
|                         version >= ORG_KDE_KWIN_IDLE_TIMEOUT_IDLE_SINCE_VERSION) { | ||||
|                 ctx.idle_handler = wl_registry_bind(registry, name, &org_kde_kwin_idle_interface, 1); | ||||
|         } | ||||
| } | ||||
| 
 | ||||
| static void handle_global_remove(void *data, struct wl_registry *registry, | ||||
|                 uint32_t name) { | ||||
|         struct wl_output *output, *tmp; | ||||
|         struct dunst_output *output, *tmp; | ||||
|         wl_list_for_each_safe(output, tmp, &ctx.outputs, link) { | ||||
|                 if (output->global_name == name) { | ||||
|                         destroy_output(output); | ||||
| @ -407,7 +442,7 @@ bool init_wayland() { | ||||
|         } | ||||
| 
 | ||||
|         if (ctx.xdg_output_manager != NULL) { | ||||
|                 struct wl_output *output; | ||||
|                 struct dunst_output *output; | ||||
|                 wl_list_for_each(output, &ctx.outputs, link) { | ||||
|                         get_xdg_output(output); | ||||
|                 } | ||||
| @ -432,7 +467,7 @@ void finish_wayland() { | ||||
|         finish_buffer(&ctx.buffers[0]); | ||||
|         finish_buffer(&ctx.buffers[1]); | ||||
| 
 | ||||
|         struct wl_output *output, *output_tmp; | ||||
|         struct dunst_output *output, *output_tmp; | ||||
|         wl_list_for_each_safe(output, output_tmp, &ctx.outputs, link) { | ||||
|                 destroy_output(output); | ||||
|         } | ||||
| @ -449,9 +484,9 @@ void finish_wayland() { | ||||
|         wl_display_disconnect(ctx.display); | ||||
| } | ||||
| 
 | ||||
| static struct wl_output *get_configured_output() { | ||||
|         struct wl_output *output; | ||||
|         // FIXME
 | ||||
| static struct dunst_output *get_configured_output() { | ||||
|         struct dunst_output *output; | ||||
|         // FIXME Make sure the returned output corresponds to the monitor number configured in the dunstrc
 | ||||
|         wl_list_for_each(output, &ctx.outputs, link) { | ||||
|                 return output; | ||||
|         } | ||||
| @ -465,12 +500,12 @@ static void schedule_frame_and_commit(); | ||||
| static void send_frame() { | ||||
|         int scale = 1; | ||||
| 
 | ||||
|         struct wl_output *output = get_configured_output(); | ||||
|         struct dunst_output *output = get_configured_output(); | ||||
|         int height = ctx.cur_dim.h; | ||||
| 
 | ||||
|         // There are two cases where we want to tear down the surface: zero
 | ||||
|         // notifications (height = 0) or moving between outputs.
 | ||||
|         if (height == 0 || ctx.layer_surface_output != output) { | ||||
|         if (height == 0 || ctx.layer_surface_output != output->wl_output) { | ||||
|                 if (ctx.layer_surface != NULL) { | ||||
|                         zwlr_layer_surface_v1_destroy(ctx.layer_surface); | ||||
|                         ctx.layer_surface = NULL; | ||||
| @ -498,10 +533,11 @@ static void send_frame() { | ||||
|         if (ctx.layer_surface == NULL) { | ||||
|                 struct wl_output *wl_output = NULL; | ||||
|                 if (output != NULL) { | ||||
|                         LOG_I("Output is not null"); | ||||
|                         wl_output = output->wl_output; | ||||
|                 } | ||||
|                 ctx.layer_surface_output = output; | ||||
| 
 | ||||
|                 } else | ||||
|                         LOG_I("output is null"); | ||||
|                 ctx.layer_surface_output = output->wl_output; | ||||
|                 ctx.surface = wl_compositor_create_surface(ctx.compositor); | ||||
|                 wl_surface_add_listener(ctx.surface, &surface_listener, NULL); | ||||
| 
 | ||||
| @ -707,7 +743,14 @@ const struct screen_info* wl_get_active_screen(void) { | ||||
| } | ||||
| 
 | ||||
| bool wl_is_idle(void) { | ||||
|         return false; | ||||
|         LOG_I("Idle status queried: %i", ctx.is_idle); | ||||
|         // When the user doesn't have a seat, or their compositor doesn't support the idle
 | ||||
|         // protocol, we'll assume that they are not idle.
 | ||||
|         if (settings.idle_threshold == 0 || ctx.has_seat == false || ctx.idle_handler == NULL) { | ||||
|                 return false; | ||||
|         } else { | ||||
|                 return ctx.is_idle; | ||||
|         } | ||||
| } | ||||
| bool wl_have_fullscreen_window(void) { | ||||
|         return false; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 fwsmit
						fwsmit