Merge pull request #651 from bebehei/dunstctl
Implement a command line control (dunstctl)
This commit is contained in:
		
						commit
						337ff1edb5
					
				
							
								
								
									
										25
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								Makefile
									
									
									
									
									
								
							| @ -106,9 +106,15 @@ test/test: ${OBJ} ${TEST_OBJ} | ||||
| 	${CC} -o ${@} ${TEST_OBJ} $(filter-out ${TEST_OBJ:test/%=src/%},${OBJ}) ${CFLAGS} ${LDFLAGS} | ||||
| 
 | ||||
| .PHONY: doc doc-doxygen | ||||
| doc: docs/dunst.1 | ||||
| doc: docs/dunst.1 docs/dunstctl.1 | ||||
| 
 | ||||
| # Can't dedup this as we need to explicitly provide the name and title text to
 | ||||
| # pod2man :(
 | ||||
| docs/dunst.1: docs/dunst.pod | ||||
| 	${POD2MAN} --name=dunst -c "Dunst Reference" --section=1 --release=${VERSION} $< > $@ | ||||
| docs/dunstctl.1: docs/dunstctl.pod | ||||
| 	${POD2MAN} --name=dunstctl -c "dunstctl reference" --section=1 --release=${VERSION} $< > $@ | ||||
| 
 | ||||
| doc-doxygen: | ||||
| 	${DOXYGEN} docs/internal/Doxyfile | ||||
| 
 | ||||
| @ -137,6 +143,7 @@ clean-dunstify: | ||||
| 
 | ||||
| clean-doc: | ||||
| 	rm -f docs/dunst.1 | ||||
| 	rm -f docs/dunstctl.1 | ||||
| 	rm -fr docs/internal/html | ||||
| 	rm -fr docs/internal/coverage | ||||
| 
 | ||||
| @ -151,15 +158,19 @@ clean-coverage-run: | ||||
| 	${FIND} . -type f -name '*.gcov' -delete | ||||
| 	${FIND} . -type f -name '*.gcda' -delete | ||||
| 
 | ||||
| .PHONY: install install-dunst install-doc \ | ||||
| .PHONY: install install-dunst install-dunstctl install-doc \ | ||||
|         install-service install-service-dbus install-service-systemd \
 | ||||
|         uninstall \
 | ||||
|         uninstall uninstall-dunstctl \
 | ||||
|         uninstall-service uninstall-service-dbus uninstall-service-systemd | ||||
| install: install-dunst install-doc install-service install-dunstify | ||||
| install: install-dunst install-dunstctl install-doc install-service install-dunstify | ||||
| 
 | ||||
| install-dunst: dunst doc | ||||
| 	install -Dm755 dunst ${DESTDIR}${BINDIR}/dunst | ||||
| 	install -Dm644 docs/dunst.1 ${DESTDIR}${MANPREFIX}/man1/dunst.1 | ||||
| 	install -Dm644 docs/dunstctl.1 ${DESTDIR}${MANPREFIX}/man1/dunstctl.1 | ||||
| 
 | ||||
| install-dunstctl: dunstctl | ||||
| 	install -Dm755 dunstctl ${DESTDIR}${BINDIR}/dunstctl | ||||
| 
 | ||||
| install-doc: | ||||
| 	install -Dm644 dunstrc ${DESTDIR}${DATADIR}/dunst/dunstrc | ||||
| @ -176,12 +187,16 @@ endif | ||||
| install-dunstify: dunstify | ||||
| 	install -Dm755 dunstify ${DESTDIR}${BINDIR}/dunstify | ||||
| 
 | ||||
| uninstall: uninstall-service | ||||
| uninstall: uninstall-service uninstall-dunstctl | ||||
| 	rm -f ${DESTDIR}${BINDIR}/dunst | ||||
| 	rm -f ${DESTDIR}${BINDIR}/dunstify | ||||
| 	rm -f ${DESTDIR}${MANPREFIX}/man1/dunst.1 | ||||
| 	rm -f ${DESTDIR}${MANPREFIX}/man1/dunstctl.1 | ||||
| 	rm -rf ${DESTDIR}${DATADIR}/dunst | ||||
| 
 | ||||
| uninstall-dunstctl: | ||||
| 	rm -f ${DESTDIR}${BINDIR}/dunstctl | ||||
| 
 | ||||
| uninstall-service: uninstall-service-dbus | ||||
| uninstall-service-dbus: | ||||
| 	rm -f ${DESTDIR}${SERVICEDIR_DBUS}/org.knopwob.dunst.service | ||||
|  | ||||
| @ -517,7 +517,7 @@ Close all notifications. | ||||
| 
 | ||||
| =back | ||||
| 
 | ||||
| =head2 Shortcut section | ||||
| =head2 Shortcut section B<DEPRECATED SEE DUNSTCTL> | ||||
| 
 | ||||
| Keyboard shortcuts are defined in the following format: "Modifier+key" where the | ||||
| modifier is one of ctrl,mod1,mod2,mod3,mod4 and key is any keyboard key. | ||||
| @ -602,6 +602,13 @@ See TIME FORMAT for valid times. | ||||
| 
 | ||||
| =back | ||||
| 
 | ||||
| =head1 DUNSTCTL | ||||
| 
 | ||||
| Dunst now contains a command line control command that can be used to interact | ||||
| with it. It supports all functions previously done only via keyboard shortcuts | ||||
| but also has a lot of extra functionality. So see more see the dunstctl man | ||||
| page. | ||||
| 
 | ||||
| =head1 HISTORY | ||||
| 
 | ||||
| Dunst saves a number of notifications (specified by B<history_length>) in memory. | ||||
| @ -865,9 +872,8 @@ Example time: "1000ms" "10m" | ||||
| 
 | ||||
| =head1 MISCELLANEOUS | ||||
| 
 | ||||
| Dunst can be paused by sending a notification with a summary of | ||||
| "DUNST_COMMAND_PAUSE", resumed with a summary of "DUNST_COMMAND_RESUME" and | ||||
| toggled with a summary of "DUNST_COMMAND_TOGGLE". | ||||
| Dunst can be paused via the `dunstctl set-running false` command. To unpause dunst use | ||||
| `dunstctl set-status true` and to unpause `dunstctl set-status false`. | ||||
| Alternatively you can send SIGUSR1 and SIGUSR2 to pause and unpause | ||||
| respectively. For Example: | ||||
| 
 | ||||
| @ -908,4 +914,4 @@ If you feel that copyrights are violated, please send me an email. | ||||
| 
 | ||||
| =head1 SEE ALSO | ||||
| 
 | ||||
| dwm(1), dmenu(1), twmn(1), notify-send(1) | ||||
| dunstctl(1), dwm(1), dmenu(1), twmn(1), notify-send(1) | ||||
|  | ||||
							
								
								
									
										59
									
								
								docs/dunstctl.pod
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								docs/dunstctl.pod
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | ||||
| =head1 NAME | ||||
| 
 | ||||
| dunstctl - Command line control utility for dunst, a customizable and lightweight notification-daemon | ||||
| 
 | ||||
| =head1 SYNOPSIS | ||||
| 
 | ||||
| dunstctl COMMAND [PARAMETER] | ||||
| 
 | ||||
| =head1 COMMANDS | ||||
| 
 | ||||
| =over 4 | ||||
| 
 | ||||
| =item B<action> notification_position | ||||
| 
 | ||||
| Performs the default action or, if not available, opens the context menu of the | ||||
| notification at the given position (starting count at the top, first | ||||
| notification being 0).  | ||||
| 
 | ||||
| =item B<close> | ||||
| 
 | ||||
| Close the topmost notification currently being displayed. | ||||
| 
 | ||||
| =item B<close-all> | ||||
| 
 | ||||
| Close all notifications currently being displayed | ||||
| 
 | ||||
| =item B<context> | ||||
| 
 | ||||
| Open the context menu, presenting all available actions and urls for the | ||||
| currently open notifications. | ||||
| 
 | ||||
| =item B<history-pop> | ||||
| 
 | ||||
| Redisplay the notification that was most recently closed. This can be called | ||||
| multiple times to show older notifications, up to the history limit configured | ||||
| in dunst. | ||||
| 
 | ||||
| =item B<running> | ||||
| 
 | ||||
| Check if dunst is currently running or paused. If dunst is paused notifications | ||||
| will be kept but not shown until it is unpaused. | ||||
| 
 | ||||
| =item B<set-running> true/false | ||||
| 
 | ||||
| Set the paused status of dunst. If true, dunst is running normally, if false, | ||||
| dunst is paused. See the running command and the dunst man page for more | ||||
| information. | ||||
| 
 | ||||
| =item B<debug> | ||||
| 
 | ||||
| Tries to contact dunst and checks for common faults between dunstctl and dunst. | ||||
| Useful if something isn't working | ||||
| 
 | ||||
| =item B<help> | ||||
| 
 | ||||
| Show all available commands with a brief description | ||||
| 
 | ||||
| =back | ||||
| 
 | ||||
							
								
								
									
										101
									
								
								dunstctl
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										101
									
								
								dunstctl
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,101 @@ | ||||
| #!/bin/sh | ||||
| 
 | ||||
| set -eu | ||||
| 
 | ||||
| DBUS_NAME="org.freedesktop.Notifications" | ||||
| DBUS_PATH="/org/freedesktop/Notifications" | ||||
| DBUS_IFAC_DUNST="org.dunstproject.cmd0" | ||||
| DBUS_IFAC_PROP="org.freedesktop.DBus.Properties" | ||||
| DBUS_IFAC_FDN="org.freedesktop.Notifications" | ||||
| 
 | ||||
| die(){ printf "%s\n" "${1}" >&2; exit 1; } | ||||
| 
 | ||||
| show_help() { | ||||
| 	cat <<-EOH | ||||
| 	Usage: dunstctl <command> [parameters]" | ||||
| 	Commands: | ||||
| 	  action                   Perform the default action, or open the | ||||
| 	                           context menu of the notification at the | ||||
| 	                           given position | ||||
| 	  close                    Close the last notification | ||||
| 	  close-all                Close the all notifications | ||||
| 	  context                  Open context menu | ||||
| 	  history-pop              Pop one notification from history | ||||
| 	  running                  Check if dunst is running or paused | ||||
| 	  set-running [true|false] Set the pause status | ||||
| 	  debug                    Print debugging information | ||||
| 	  help                     Show this help | ||||
| 	EOH | ||||
| } | ||||
| dbus_send_checked() { | ||||
| 	dbus-send "$@" \ | ||||
| 		|| die "Failed to communicate with dunst, is it running? Or maybe the version is outdated. You can try 'dunstctl debug' as a next debugging step." | ||||
| } | ||||
| 
 | ||||
| method_call() { | ||||
| 	dbus_send_checked --print-reply=literal --dest="${DBUS_NAME}" "${DBUS_PATH}" "$@" | ||||
| } | ||||
| 
 | ||||
| property_get() { | ||||
| 	dbus_send_checked --print-reply=literal --dest="${DBUS_NAME}" "${DBUS_PATH}" "${DBUS_IFAC_PROP}.Get" "string:${DBUS_IFAC_DUNST}" "string:${1}" | ||||
| } | ||||
| 
 | ||||
| property_set() { | ||||
| 	dbus_send_checked --print-reply=literal --dest="${DBUS_NAME}" "${DBUS_PATH}" "${DBUS_IFAC_PROP}.Set" "string:${DBUS_IFAC_DUNST}" "string:${1}" "${2}" | ||||
| } | ||||
| 
 | ||||
| command -v dbus-send >/dev/null 2>/dev/null || \ | ||||
| 	die "Command dbus-send not found" | ||||
| 
 | ||||
| 
 | ||||
| case "${1:-}" in | ||||
| 	"action") | ||||
| 		method_call "${DBUS_IFAC_DUNST}.NotificationAction" "int32:${2:-0}" >/dev/null | ||||
| 		;; | ||||
| 	"close") | ||||
| 		method_call "${DBUS_IFAC_DUNST}.NotificationCloseLast" >/dev/null | ||||
| 		;; | ||||
| 	"close-all") | ||||
| 		method_call "${DBUS_IFAC_DUNST}.NotificationCloseAll" >/dev/null | ||||
| 		;; | ||||
| 	"context") | ||||
| 		method_call "${DBUS_IFAC_DUNST}.ContextMenuCall" >/dev/null | ||||
| 		;; | ||||
| 	"history-pop") | ||||
| 		method_call "${DBUS_IFAC_DUNST}.NotificationShow" >/dev/null | ||||
| 		;; | ||||
| 	"running") | ||||
| 		property_get running | ( read -r _ _ paused; printf "%s\n" "${paused}"; ) | ||||
| 		;; | ||||
| 	"set-running") | ||||
| 		[ "${2:-}" ] \ | ||||
| 			|| die "No status parameter specified. Please give either 'true' or 'false' as running parameter." | ||||
| 		[ "${2}" = "true" ] || [ "${2}" = "false" ] \ | ||||
| 			|| die "Please give either 'true' or 'false' as running parameter." | ||||
| 		property_set running variant:boolean:"${2}" | ||||
| 		;; | ||||
| 	"help"|"--help"|"-h") | ||||
| 		show_help | ||||
| 		;; | ||||
| 	"debug") | ||||
| 		dbus-send --print-reply=literal --dest="${DBUS_NAME}" "${DBUS_PATH}" "${DBUS_IFAC_FDN}.GetServerInformation" >/dev/null 2>/dev/null \ | ||||
| 			|| die "Dunst is not running." | ||||
| 
 | ||||
| 		dbus-send --print-reply=literal --dest="${DBUS_NAME}" "${DBUS_PATH}" "${DBUS_IFAC_FDN}.GetServerInformation" \ | ||||
| 			| ( | ||||
| 					read -r name _ version _ | ||||
| 					[ "${name}" = "dunst" ] | ||||
| 					printf "dunst version: %s\n" "${version}" | ||||
| 				) \ | ||||
| 			|| die "Another notification manager is running. It's not dunst" | ||||
| 
 | ||||
| 		dbus-send --print-reply=literal --dest="${DBUS_NAME}" "${DBUS_PATH}" "${DBUS_IFAC_DUNST}.Ping" >/dev/null 2>/dev/null \ | ||||
| 			|| die "Dunst controlling interface not available. Is the version too old?" | ||||
| 		;; | ||||
| 	"") | ||||
| 		die "dunstctl: No command specified. Please consult the usage." | ||||
| 		;; | ||||
| 	*) | ||||
| 		die "dunstctl: unrecognized command '${1:-}'. Please consult the usage." | ||||
| 		;; | ||||
| esac | ||||
							
								
								
									
										251
									
								
								src/dbus.c
									
									
									
									
									
								
							
							
						
						
									
										251
									
								
								src/dbus.c
									
									
									
									
									
								
							| @ -8,6 +8,7 @@ | ||||
| 
 | ||||
| #include "dunst.h" | ||||
| #include "log.h" | ||||
| #include "menu.h" | ||||
| #include "notification.h" | ||||
| #include "queues.h" | ||||
| #include "settings.h" | ||||
| @ -17,6 +18,12 @@ | ||||
| #define FDN_IFAC "org.freedesktop.Notifications" | ||||
| #define FDN_NAME "org.freedesktop.Notifications" | ||||
| 
 | ||||
| #define DUNST_PATH "/org/freedesktop/Notifications" | ||||
| #define DUNST_IFAC "org.dunstproject.cmd0" | ||||
| #define DUNST_NAME "org.freedesktop.Notifications" | ||||
| 
 | ||||
| #define PROPERTIES_IFAC "org.freedesktop.DBus.Properties" | ||||
| 
 | ||||
| GDBusConnection *dbus_conn; | ||||
| 
 | ||||
| static GDBusNodeInfo *introspection_data = NULL; | ||||
| @ -62,6 +69,22 @@ static const char *introspection_xml = | ||||
|     "            <arg name=\"id\"         type=\"u\"/>" | ||||
|     "            <arg name=\"action_key\" type=\"s\"/>" | ||||
|     "        </signal>" | ||||
|     "    </interface>" | ||||
|     "    <interface name=\""DUNST_IFAC"\">" | ||||
| 
 | ||||
|     "        <method name=\"ContextMenuCall\"       />" | ||||
|     "        <method name=\"NotificationAction\">" | ||||
|     "            <arg name=\"number\"     type=\"i\"/>" | ||||
|     "        </method>" | ||||
|     "        <method name=\"NotificationCloseLast\" />" | ||||
|     "        <method name=\"NotificationCloseAll\"  />" | ||||
|     "        <method name=\"NotificationShow\"      />" | ||||
|     "        <method name=\"Ping\"                  />" | ||||
| 
 | ||||
|     "        <property name=\"running\" type=\"b\" access=\"readwrite\">" | ||||
|     "            <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"true\"/>" | ||||
|     "        </property>" | ||||
| 
 | ||||
|     "    </interface>" | ||||
|     "</node>"; | ||||
| 
 | ||||
| @ -98,7 +121,6 @@ DBUS_METHOD(Notify); | ||||
| DBUS_METHOD(CloseNotification); | ||||
| DBUS_METHOD(GetCapabilities); | ||||
| DBUS_METHOD(GetServerInformation); | ||||
| 
 | ||||
| static struct dbus_method methods_fdn[] = { | ||||
|         {"CloseNotification",     dbus_cb_CloseNotification}, | ||||
|         {"GetCapabilities",       dbus_cb_GetCapabilities}, | ||||
| @ -106,7 +128,7 @@ static struct dbus_method methods_fdn[] = { | ||||
|         {"Notify",                dbus_cb_Notify}, | ||||
| }; | ||||
| 
 | ||||
| void handle_method_call(GDBusConnection *connection, | ||||
| void dbus_cb_fdn_methods(GDBusConnection *connection, | ||||
|                         const gchar *sender, | ||||
|                         const gchar *object_path, | ||||
|                         const gchar *interface_name, | ||||
| @ -115,9 +137,9 @@ void handle_method_call(GDBusConnection *connection, | ||||
|                         GDBusMethodInvocation *invocation, | ||||
|                         gpointer user_data) | ||||
| { | ||||
|         struct dbus_method *m = bsearch( | ||||
|                         method_name, | ||||
|                         &methods_fdn, | ||||
| 
 | ||||
|         struct dbus_method *m = bsearch(method_name, | ||||
|                                         methods_fdn, | ||||
|                                         G_N_ELEMENTS(methods_fdn), | ||||
|                                         sizeof(struct dbus_method), | ||||
|                                         cmp_methods); | ||||
| @ -131,6 +153,144 @@ void handle_method_call(GDBusConnection *connection, | ||||
|         } | ||||
| } | ||||
| 
 | ||||
| DBUS_METHOD(dunst_ContextMenuCall); | ||||
| DBUS_METHOD(dunst_NotificationAction); | ||||
| DBUS_METHOD(dunst_NotificationCloseAll); | ||||
| DBUS_METHOD(dunst_NotificationCloseLast); | ||||
| DBUS_METHOD(dunst_NotificationShow); | ||||
| DBUS_METHOD(dunst_Ping); | ||||
| static struct dbus_method methods_dunst[] = { | ||||
|         {"ContextMenuCall",        dbus_cb_dunst_ContextMenuCall}, | ||||
|         {"NotificationAction",     dbus_cb_dunst_NotificationAction}, | ||||
|         {"NotificationCloseAll",   dbus_cb_dunst_NotificationCloseAll}, | ||||
|         {"NotificationCloseLast",  dbus_cb_dunst_NotificationCloseLast}, | ||||
|         {"NotificationShow",       dbus_cb_dunst_NotificationShow}, | ||||
|         {"Ping",                   dbus_cb_dunst_Ping}, | ||||
| }; | ||||
| 
 | ||||
| void dbus_cb_dunst_methods(GDBusConnection *connection, | ||||
|                            const gchar *sender, | ||||
|                            const gchar *object_path, | ||||
|                            const gchar *interface_name, | ||||
|                            const gchar *method_name, | ||||
|                            GVariant *parameters, | ||||
|                            GDBusMethodInvocation *invocation, | ||||
|                            gpointer user_data) | ||||
| { | ||||
| 
 | ||||
|         struct dbus_method *m = bsearch(method_name, | ||||
|                                         methods_dunst, | ||||
|                                         G_N_ELEMENTS(methods_dunst), | ||||
|                                         sizeof(struct dbus_method), | ||||
|                                         cmp_methods); | ||||
| 
 | ||||
|         if (m) { | ||||
|                 m->method(connection, sender, parameters, invocation); | ||||
|         } else { | ||||
|                 LOG_M("Unknown method name: '%s' (sender: '%s').", | ||||
|                       method_name, | ||||
|                       sender); | ||||
|         } | ||||
| } | ||||
| 
 | ||||
| static void dbus_cb_dunst_ContextMenuCall(GDBusConnection *connection, | ||||
|                                           const gchar *sender, | ||||
|                                           GVariant *parameters, | ||||
|                                           GDBusMethodInvocation *invocation) | ||||
| { | ||||
|         LOG_D("CMD: Calling context menu"); | ||||
|         context_menu(); | ||||
| 
 | ||||
|         g_dbus_method_invocation_return_value(invocation, NULL); | ||||
|         g_dbus_connection_flush(connection, NULL, NULL, NULL); | ||||
| } | ||||
| 
 | ||||
| static void dbus_cb_dunst_NotificationAction(GDBusConnection *connection, | ||||
|                                              const gchar *sender, | ||||
|                                              GVariant *parameters, | ||||
|                                              GDBusMethodInvocation *invocation) | ||||
| { | ||||
|         int notification_nr = 0; | ||||
|         g_variant_get(parameters, "(i)", ¬ification_nr); | ||||
| 
 | ||||
|         LOG_D("CMD: Calling action for notification %d", notification_nr); | ||||
| 
 | ||||
|         if (notification_nr < 0 || queues_length_waiting() < notification_nr) { | ||||
|                 g_dbus_method_invocation_return_error(invocation, | ||||
|                         G_DBUS_ERROR, | ||||
|                         G_DBUS_ERROR_INVALID_ARGS, | ||||
|                         "Couldn't activate action for notification in position %d, %d notifications currently open", | ||||
|                         notification_nr, queues_length_waiting()); | ||||
|                 return; | ||||
|         } | ||||
| 
 | ||||
|         const GList *list = g_list_nth_data(queues_get_displayed(), notification_nr); | ||||
| 
 | ||||
|         if (list && list->data) { | ||||
|                 struct notification *n = list->data; | ||||
|                 LOG_D("CMD: Calling action for notification %s", n->summary); | ||||
|                 notification_do_action(n); | ||||
|         } | ||||
| 
 | ||||
|         g_dbus_method_invocation_return_value(invocation, NULL); | ||||
|         g_dbus_connection_flush(connection, NULL, NULL, NULL); | ||||
| } | ||||
| 
 | ||||
| static void dbus_cb_dunst_NotificationCloseAll(GDBusConnection *connection, | ||||
|                                               const gchar *sender, | ||||
|                                               GVariant *parameters, | ||||
|                                               GDBusMethodInvocation *invocation) | ||||
| { | ||||
|         LOG_D("CMD: Pushing all to history"); | ||||
|         queues_history_push_all(); | ||||
|         wake_up(); | ||||
| 
 | ||||
|         g_dbus_method_invocation_return_value(invocation, NULL); | ||||
|         g_dbus_connection_flush(connection, NULL, NULL, NULL); | ||||
| } | ||||
| 
 | ||||
| static void dbus_cb_dunst_NotificationCloseLast(GDBusConnection *connection, | ||||
|                                                 const gchar *sender, | ||||
|                                                 GVariant *parameters, | ||||
|                                                 GDBusMethodInvocation *invocation) | ||||
| { | ||||
|         LOG_D("CMD: Closing last notification"); | ||||
|         const GList *list = queues_get_displayed(); | ||||
|         if (list && list->data) { | ||||
|                 struct notification *n = list->data; | ||||
|                 queues_notification_close_id(n->id, REASON_USER); | ||||
|                 wake_up(); | ||||
|         } | ||||
| 
 | ||||
|         g_dbus_method_invocation_return_value(invocation, NULL); | ||||
|         g_dbus_connection_flush(connection, NULL, NULL, NULL); | ||||
| } | ||||
| 
 | ||||
| static void dbus_cb_dunst_NotificationShow(GDBusConnection *connection, | ||||
|                                            const gchar *sender, | ||||
|                                            GVariant *parameters, | ||||
|                                            GDBusMethodInvocation *invocation) | ||||
| { | ||||
|         LOG_D("CMD: Showing last notification from history"); | ||||
|         queues_history_pop(); | ||||
|         wake_up(); | ||||
| 
 | ||||
|         g_dbus_method_invocation_return_value(invocation, NULL); | ||||
|         g_dbus_connection_flush(connection, NULL, NULL, NULL); | ||||
| } | ||||
| 
 | ||||
| /* Just a simple Ping command to give the ability to dunstctl to test for the existence of this interface
 | ||||
|  * Any other way requires parsing the XML of the Introspection or other foo. Just calling the Ping on an old dunst version will fail. */ | ||||
| static void dbus_cb_dunst_Ping(GDBusConnection *connection, | ||||
|                                const gchar *sender, | ||||
|                                GVariant *parameters, | ||||
|                                GDBusMethodInvocation *invocation) | ||||
| { | ||||
|         g_dbus_method_invocation_return_value(invocation, NULL); | ||||
|         g_dbus_connection_flush(connection, NULL, NULL, NULL); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void dbus_cb_GetCapabilities( | ||||
|                 GDBusConnection *connection, | ||||
|                 const gchar *sender, | ||||
| @ -347,11 +507,9 @@ static void dbus_cb_GetServerInformation( | ||||
|                 GVariant *parameters, | ||||
|                 GDBusMethodInvocation *invocation) | ||||
| { | ||||
|         GVariant *value; | ||||
| 
 | ||||
|         value = g_variant_new("(ssss)", "dunst", "knopwob", VERSION, "1.2"); | ||||
|         g_dbus_method_invocation_return_value(invocation, value); | ||||
|         GVariant *answer = g_variant_new("(ssss)", "dunst", "knopwob", VERSION, "1.2"); | ||||
| 
 | ||||
|         g_dbus_method_invocation_return_value(invocation, answer); | ||||
|         g_dbus_connection_flush(connection, NULL, NULL, NULL); | ||||
| } | ||||
| 
 | ||||
| @ -420,28 +578,81 @@ void signal_action_invoked(const struct notification *n, const char *identifier) | ||||
|         } | ||||
| } | ||||
| 
 | ||||
| static const GDBusInterfaceVTable interface_vtable = { | ||||
|         handle_method_call | ||||
| GVariant *dbus_cb_dunst_Properties_Get(GDBusConnection *connection, | ||||
|                                        const gchar *sender, | ||||
|                                        const gchar *object_path, | ||||
|                                        const gchar *interface_name, | ||||
|                                        const gchar *property_name, | ||||
|                                        GError **error, | ||||
|                                        gpointer user_data) | ||||
| { | ||||
|         struct dunst_status status = dunst_status_get(); | ||||
| 
 | ||||
|         if (STR_EQ(property_name, "running")) { | ||||
|                 return g_variant_new_boolean(status.running); | ||||
|         } else { | ||||
|                 LOG_W("Unknown property!\n"); | ||||
|                 *error = g_error_new(G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property"); | ||||
|                 return NULL; | ||||
|         } | ||||
| } | ||||
| 
 | ||||
| gboolean dbus_cb_dunst_Properties_Set(GDBusConnection *connection, | ||||
|                                       const gchar *sender, | ||||
|                                       const gchar *object_path, | ||||
|                                       const gchar *interface_name, | ||||
|                                       const gchar *property_name, | ||||
|                                       GVariant *value, | ||||
|                                       GError **error, | ||||
|                                       gpointer user_data) | ||||
| { | ||||
|         if (STR_EQ(property_name, "running")) { | ||||
|                 dunst_status(S_RUNNING, g_variant_get_boolean(value)); | ||||
|                 wake_up(); | ||||
|                 return true; | ||||
|         } | ||||
| 
 | ||||
|         *error = g_error_new(G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property"); | ||||
| 
 | ||||
|         return false; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static const GDBusInterfaceVTable interface_vtable_fdn = { | ||||
|         dbus_cb_fdn_methods | ||||
| }; | ||||
| 
 | ||||
| static const GDBusInterfaceVTable interface_vtable_dunst = { | ||||
|         dbus_cb_dunst_methods, | ||||
|         dbus_cb_dunst_Properties_Get, | ||||
|         dbus_cb_dunst_Properties_Set, | ||||
| }; | ||||
| 
 | ||||
| static void dbus_cb_bus_acquired(GDBusConnection *connection, | ||||
|                                  const gchar *name, | ||||
|                                  gpointer user_data) | ||||
| { | ||||
|         guint registration_id; | ||||
| 
 | ||||
|         GError *err = NULL; | ||||
| 
 | ||||
|         registration_id = g_dbus_connection_register_object(connection, | ||||
|         if(!g_dbus_connection_register_object( | ||||
|                                 connection, | ||||
|                                 FDN_PATH, | ||||
|                                 introspection_data->interfaces[0], | ||||
|                                                             &interface_vtable, | ||||
|                                 &interface_vtable_fdn, | ||||
|                                 NULL, | ||||
|                                 NULL, | ||||
|                                                             &err); | ||||
|                                 &err)) { | ||||
|                 DIE("Unable to register dbus connection interface '%s': %s", introspection_data->interfaces[0]->name, err->message); | ||||
|         } | ||||
| 
 | ||||
|         if (registration_id == 0) { | ||||
|                 DIE("Unable to register dbus connection: %s", err->message); | ||||
|         if(!g_dbus_connection_register_object( | ||||
|                                 connection, | ||||
|                                 FDN_PATH, | ||||
|                                 introspection_data->interfaces[1], | ||||
|                                 &interface_vtable_dunst, | ||||
|                                 NULL, | ||||
|                                 NULL, | ||||
|                                 &err)) { | ||||
|                 DIE("Unable to register dbus connection interface '%s': %s", introspection_data->interfaces[1]->name, err->message); | ||||
|         } | ||||
| } | ||||
| 
 | ||||
| @ -449,6 +660,8 @@ static void dbus_cb_name_acquired(GDBusConnection *connection, | ||||
|                                   const gchar *name, | ||||
|                                   gpointer user_data) | ||||
| { | ||||
|         // If we're not able to get org.fd.N bus, we've still got a problem
 | ||||
|         if (STR_EQ(name, FDN_NAME)) | ||||
|                 dbus_conn = connection; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -3,6 +3,7 @@ | ||||
| #ifndef DUNST_DBUS_H | ||||
| #define DUNST_DBUS_H | ||||
| 
 | ||||
| #include "dunst.h" | ||||
| #include "notification.h" | ||||
| 
 | ||||
| /// The reasons according to the notification spec
 | ||||
|  | ||||
| @ -799,6 +799,12 @@ TEST assert_methodlists_sorted(void) | ||||
|                                 methods_fdn[i+1].method_name)); | ||||
|         } | ||||
| 
 | ||||
|         for (size_t i = 0; i+1 < G_N_ELEMENTS(methods_dunst); i++) { | ||||
|                 ASSERT(0 > strcmp( | ||||
|                                 methods_dunst[i].method_name, | ||||
|                                 methods_dunst[i+1].method_name)); | ||||
|         } | ||||
| 
 | ||||
|         PASS(); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,6 +1,15 @@ | ||||
| #define dbus_signal_status_changed(status) signal_sent_stub(status) | ||||
| #include "../src/dunst.c" | ||||
| #include "greatest.h" | ||||
| 
 | ||||
| static bool signal_sent = false; | ||||
| 
 | ||||
| void signal_sent_stub(struct dunst_status status) | ||||
| { | ||||
|         signal_sent = true; | ||||
|         return; | ||||
| } | ||||
| 
 | ||||
| TEST test_dunst_status(void) | ||||
| { | ||||
|         status = (struct dunst_status) {false, false, false}; | ||||
|  | ||||
| @ -9,10 +9,12 @@ make -C "${BASE}" SYSTEMD=1 SERVICEDIR_SYSTEMD="${PREFIX}/systemd" SERVICEDIR_DB | ||||
| 
 | ||||
| diff -u <(find "${PREFIX}" -type f -printf "%P\n" | sort) - <<EOF | ||||
| bin/dunst | ||||
| bin/dunstctl | ||||
| bin/dunstify | ||||
| dbus/org.knopwob.dunst.service | ||||
| share/dunst/dunstrc | ||||
| share/man/man1/dunst.1 | ||||
| share/man/man1/dunstctl.1 | ||||
| systemd/dunst.service | ||||
| EOF | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Nikos Tsipinakis
						Nikos Tsipinakis