@@ 22,6 22,7 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
+#include <errno.h>
#include <wayland-client.h>
@@ 31,42 32,55 @@
#define VERSION "0.0.1"
const char usage[] =
- "Usage:\n"
- "\twlopm List outputs and their power modes.\n"
- "\twlopm --json Format the list as JSON.\n"
- "\twlopm on <output-name> Set output power mode to on.\n"
- "\twlopm off <output-name> Set output power mode to off.\n"
- "\twlopm toggle <output-name> Toggle output power mode.\n"
+ "Usage: wlopm [options...]\n"
+ " -j, --json Use JSON format.\n"
+ " -h, --help Print this help text and exit.\n"
+ " --on <output-name> Set the power mode of the specified output to on.\n"
+ " --off <output-name> Set the power mode of the specified output to off.\n"
+ " --toggle <output-name> Toggle the power mode of the specified output.\n"
"\n";
+struct Output
+{
+ struct wl_list link;
+ struct wl_output *wl_output;
+ struct zxdg_output_v1 *xdg_output;
+ struct zwlr_output_power_v1 *wlr_output_power;
+ enum zwlr_output_power_v1_mode mode;
+ char *name;
+ bool operation_failed;
+ uint32_t global_name;
+};
+
enum Action
{
LIST,
+ OPERATIONS,
+};
+
+enum Power_mode
+{
ON,
OFF,
TOGGLE,
};
-enum Action action = LIST;
-bool json = false;
-char *name = NULL;
-
-struct Output
+struct Operation
{
struct wl_list link;
- struct wl_output *wl_output;
- struct zxdg_output_v1 *xdg_output;
- struct zwlr_output_power_v1 *wlr_output_power;
- enum zwlr_output_power_v1_mode mode;
char *name;
- uint32_t global_name;
+ enum Power_mode power_mode;
};
+bool json = false;
+bool json_prev = false;
+
struct wl_display *wl_display = NULL;
struct wl_registry *wl_registry = NULL;
struct wl_callback *sync_callback = NULL;
struct wl_list outputs;
+struct wl_list operations;
struct zxdg_output_manager_v1 *xdg_output_manager = NULL;
struct zwlr_output_power_manager_v1 *wlr_output_power_manager = NULL;
@@ 86,9 100,7 @@ static void wlr_output_power_handle_mode (void *data, struct zwlr_output_power_v
static void wlr_output_power_handle_failed (void *data, struct zwlr_output_power_v1 *wlr_output_power)
{
struct Output *output = (struct Output *)data;
- fprintf(stderr, "ERROR: Setting mode for output \"%s\" failed.\n", output->name);
- loop = false;
- ret = EXIT_FAILURE;
+ output->operation_failed = true;
}
static const struct zwlr_output_power_v1_listener wlr_output_power_listener = {
@@ 156,7 168,7 @@ static struct Output *output_from_name (const char *str)
{
struct Output *output;
wl_list_for_each(output, &outputs, link)
- if ( strcmp(output->name, name) == 0 )
+ if ( strcmp(output->name, str) == 0 )
return output;
return NULL;
}
@@ 209,22 221,28 @@ static void sync_handle_done (void *data, struct wl_callback *wl_callback, uint3
}
else if ( sync == 1 )
{
- if ( action == LIST )
+ if (wl_list_empty(&operations))
{
+ /* The operations list is empty, so let's just list all
+ * outputs and their current power mode.
+ */
struct Output *output;
if (json)
{
- fputs("[\n", stdout);
- uint32_t i = 0, len = (uint32_t)wl_list_length(&outputs);
+ fputs("[", stdout);
wl_list_for_each(output, &outputs, link)
{
- fprintf(stdout, " {\n \"output\": \"%s\",\n \"power-mode\": \"%s\"\n }%s\n",
+ fprintf(stdout,
+ "%s\n {\n"
+ " \"output\": \"%s\",\n"
+ " \"power-mode\": \"%s\"\n"
+ " }",
+ json_prev ? "," : "",
output->name,
- power_mode_to_string(output->mode),
- i < (len - 1) ? "," : "");
- i++;
+ power_mode_to_string(output->mode));
+ json_prev = true;
}
- fputs("]\n", stdout);
+ fputs("\n]\n", stdout);
}
else
wl_list_for_each(output, &outputs, link)
@@ 234,87 252,217 @@ static void sync_handle_done (void *data, struct wl_callback *wl_callback, uint3
}
else
{
- const struct Output *output = output_from_name(name);
- if ( output == NULL )
- {
- fprintf(stdout, "ERROR: No output with name \"%s\".\n", name);
- ret = EXIT_FAILURE;
- loop = false;
- return;
- }
+ /* There are operations in the operations list. We have
+ * things to do!
+ */
+
+ if (json)
+ fputs(
+ "{\n"
+ " \"errors\": [",
+ stdout);
- enum zwlr_output_power_v1_mode new_mode;
- switch (action)
+ struct Operation *operation;
+ wl_list_for_each(operation, &operations, link)
{
- case ON:
- new_mode = ZWLR_OUTPUT_POWER_V1_MODE_ON;
- break;
+ const struct Output *output = output_from_name(operation->name);
+ if ( output == NULL )
+ {
+ if (json)
+ {
+ fprintf(stdout,
+ "%s\n {\n"
+ " \"output\": \"%s\",\n"
+ " \"error\": \"output does not exist\"\n"
+ " }",
+ json_prev ? "," : "",
+ operation->name);
+ json_prev = true;
+ }
+ else
+ fprintf(stderr, "ERROR: Output '%s' does not exist.\n",
+ operation->name);
+ continue;
+ }
- case OFF:
- new_mode = ZWLR_OUTPUT_POWER_V1_MODE_OFF;
- break;
+ enum zwlr_output_power_v1_mode new_mode;
+ switch (operation->power_mode)
+ {
+ case ON:
+ new_mode = ZWLR_OUTPUT_POWER_V1_MODE_ON;
+ break;
- case TOGGLE:
- if ( output->mode == ZWLR_OUTPUT_POWER_V1_MODE_ON )
+ case OFF:
new_mode = ZWLR_OUTPUT_POWER_V1_MODE_OFF;
- else
- new_mode = ZWLR_OUTPUT_POWER_V1_MODE_ON;
- break;
+ break;
+
+ case TOGGLE:
+ if ( output->mode == ZWLR_OUTPUT_POWER_V1_MODE_ON )
+ new_mode = ZWLR_OUTPUT_POWER_V1_MODE_OFF;
+ else
+ new_mode = ZWLR_OUTPUT_POWER_V1_MODE_ON;
+ break;
+ }
- case LIST:
- /* unreachable */
- break;
+ zwlr_output_power_v1_set_mode(output->wlr_output_power, new_mode);
}
- zwlr_output_power_v1_set_mode(output->wlr_output_power, new_mode);
/* We need to sync yet another time because setting the
- * power mode might fail.
+ * power mode might fail and we want to display those
+ * error messages.
*/
sync_callback = wl_display_sync(wl_display);
wl_callback_add_listener(sync_callback, &sync_callback_listener, NULL);
}
}
else
+ {
+
+ struct Output *output;
+ wl_list_for_each(output, &outputs, link)
+ if (output->operation_failed)
+ {
+ if (json)
+ {
+ fprintf(stdout,
+ "%s\n {\n"
+ " \"output\": \"%s\","
+ " \"error\": \"setting power mode failed\"\n"
+ " }",
+ json_prev ? "," : "",
+ output->name);
+ json_prev = true;
+ }
+ else
+ fprintf(stderr, "ERROR: Setting power mode for output '%s' failed.\n",
+ output->name);
+ }
+
+ if (json)
+ fputs(
+ "\n ]\n"
+ "}\n",
+ stdout);
loop = false;
+ }
sync++;
}
-int main(int argc, char *argv[])
+static void destroy_all_outputs (void)
+{
+ struct Output *output, *tmp;
+ wl_list_for_each_safe(output, tmp, &outputs, link)
+ {
+ if ( output->wlr_output_power != NULL )
+ zwlr_output_power_v1_destroy(output->wlr_output_power);
+ if ( output->xdg_output != NULL )
+ zxdg_output_v1_destroy(output->xdg_output);
+ wl_output_destroy(output->wl_output);
+ wl_list_remove(&output->link);
+ free(output->name);
+ free(output);
+ }
+}
+
+static void destroy_all_operations (void)
{
- switch (argc)
+ struct Operation *operation, *tmp;
+ wl_list_for_each_safe(operation, tmp, &operations, link)
{
- case 1:
- break;
+ wl_list_remove(&operation->link);
+ free(operation->name);
+ free(operation);
+ }
+}
- case 2:
- if ( strcmp(argv[1], "--json") == 0 )
- json = true;
- else
+static bool create_operation (const char *name, enum Power_mode power_mode)
+{
+ struct Operation *operation = calloc(1, sizeof(struct Operation));
+ if ( operation == NULL )
+ {
+ fprintf(stderr, "ERROR: calloc: %s\n", strerror(errno));
+ return false;
+ }
+
+ operation->name = strdup(name);
+ if ( operation->name == NULL )
+ {
+ fprintf(stderr, "ERROR: calloc: %s\n", strerror(errno));
+ free(operation);
+ return false;
+ }
+
+ operation->power_mode = power_mode;
+
+ wl_list_insert(&operations, &operation->link);
+ return true;
+}
+
+int main(int argc, char *argv[])
+{
+ wl_list_init(&operations);
+ for (int i = 1; i < argc; i++)
+ {
+ if ( strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0 )
+ {
+ destroy_all_operations();
+ fputs(usage, stderr);
+ return EXIT_SUCCESS;
+ }
+ else if ( strcmp(argv[i], "-j") == 0 || strcmp(argv[i], "--json") == 0 )
+ json = true;
+ else if ( strcmp(argv[i], "--on") == 0 )
+ {
+ if ( i == argc - 1 )
{
- fputs(usage, stderr);
+ fputs("ERROR: '--on' needs an output name.\n", stderr);
+ destroy_all_operations();
return EXIT_FAILURE;
}
- break;
-
- case 3:
- if ( strcmp(argv[1], "on") == 0 )
- action = ON;
- else if ( strcmp(argv[1], "off") == 0 )
- action = OFF;
- else if ( strcmp(argv[1], "toggle") == 0 )
- action = TOGGLE;
- else
+ if (! create_operation(argv[i+1], ON))
{
- fputs(usage, stderr);
+ destroy_all_operations();
return EXIT_FAILURE;
}
- name = strdup(argv[2]);
- break;
-
- default:
- fputs(usage, stderr);
+ i++;
+ }
+ else if ( strcmp(argv[i], "--off") == 0 )
+ {
+ if ( i == argc - 1 )
+ {
+ fputs("ERROR: '--off' needs an output name.\n", stderr);
+ destroy_all_operations();
+ return EXIT_FAILURE;
+ }
+ if (! create_operation(argv[i+1], OFF))
+ {
+ destroy_all_operations();
+ return EXIT_FAILURE;
+ }
+ i++;
+ }
+ else if ( strcmp(argv[i], "--toggle") == 0 )
+ {
+ if ( i == argc - 1 )
+ {
+ fputs("ERROR: '--toggle' needs an output name.\n", stderr);
+ destroy_all_operations();
+ return EXIT_FAILURE;
+ }
+ if (! create_operation(argv[i+1], TOGGLE))
+ {
+ destroy_all_operations();
+ return EXIT_FAILURE;
+ }
+ i++;
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: Unknown option '%s'\n", argv[i]);
+ destroy_all_operations();
return EXIT_FAILURE;
+ }
}
/* We query the display name here instead of letting wl_display_connect()
@@ 326,8 474,6 @@ int main(int argc, char *argv[])
if ( display_name == NULL )
{
fputs("ERROR: WAYLAND_DISPLAY is not set.\n", stderr);
- if ( name != NULL )
- free(name);
return EXIT_FAILURE;
}
@@ 335,8 481,6 @@ int main(int argc, char *argv[])
if ( wl_display == NULL )
{
fputs("ERROR: Can not connect to wayland display.\n", stderr);
- if ( name != NULL )
- free(name);
return EXIT_FAILURE;
}
@@ 350,21 494,9 @@ int main(int argc, char *argv[])
while ( loop && wl_display_dispatch(wl_display) > 0 );
- struct Output *output, *tmp;
- wl_list_for_each_safe(output, tmp, &outputs, link)
- {
- if ( output->wlr_output_power != NULL )
- zwlr_output_power_v1_destroy(output->wlr_output_power);
- if ( output->xdg_output != NULL )
- zxdg_output_v1_destroy(output->xdg_output);
- wl_output_destroy(output->wl_output);
- wl_list_remove(&output->link);
- free(output->name);
- free(output);
- }
+ destroy_all_operations();
+ destroy_all_outputs();
- if ( name != NULL )
- free(name);
if ( sync_callback != NULL )
wl_callback_destroy(sync_callback);
if ( wlr_output_power_manager != NULL )