This patch adds a wlrandr extension. It is useful to test
mode switching. The patch provides the weston-switch-mode
utility that can be use quite the same way as xrandr to
change graphical modes. For now only the DRM backend supports
mode switching, but other may follow.
---
 clients/Makefile.am   |   10 ++
 clients/switch-mode.c |  300 +++++++++++++++++++++++++++++++++++++++++++++++++
 protocol/Makefile.am  |    3 +-
 protocol/wlrandr.xml  |   62 ++++++++++
 src/Makefile.am       |    5 +
 src/compositor.c      |    1 +
 src/compositor.h      |    3 +
 src/wlrandr.c         |  105 +++++++++++++++++
 8 files changed, 488 insertions(+), 1 deletion(-)
 create mode 100644 clients/switch-mode.c
 create mode 100644 protocol/wlrandr.xml
 create mode 100644 src/wlrandr.c

diff --git a/clients/Makefile.am b/clients/Makefile.am
index 8c9bcd4..c71b94f 100644
--- a/clients/Makefile.am
+++ b/clients/Makefile.am
@@ -1,5 +1,6 @@
 bin_PROGRAMS =                                 \
        weston-info                             \
+       weston-switch-mode              \
        $(terminal)
 
 noinst_PROGRAMS =                              \
@@ -160,6 +161,13 @@ weston_info_SOURCES =                              \
        ../shared/os-compatibility.h
 weston_info_LDADD = $(WESTON_INFO_LIBS)
 
+weston_switch_mode_SOURCES =                           \
+       switch-mode.c                           \
+       ../shared/option-parser.c               \
+       wlrandr-client-protocol.h               \
+       wlrandr-protocol.c
+weston_switch_mode_LDADD = $(WESTON_INFO_LIBS)
+
 weston_desktop_shell_SOURCES =                 \
        desktop-shell.c                         \
        desktop-shell-client-protocol.h         \
@@ -173,6 +181,8 @@ weston_tablet_shell_SOURCES =                       \
 weston_tablet_shell_LDADD = libtoytoolkit.la
 
 BUILT_SOURCES =                                        \
+       wlrandr-client-protocol.h               \
+       wlrandr-protocol.c              \
        screenshooter-client-protocol.h         \
        screenshooter-protocol.c                \
        text-cursor-position-client-protocol.h  \
diff --git a/clients/switch-mode.c b/clients/switch-mode.c
new file mode 100644
index 0000000..7603fff
--- /dev/null
+++ b/clients/switch-mode.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright © 2013 Hardening <[email protected]>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <wayland-client.h>
+#include "wlrandr-client-protocol.h"
+#include "../shared/config-parser.h"
+#include "../shared/os-compatibility.h"
+
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+static struct wl_list output_list;
+static struct wlrandr *wlRandr;
+int mode_switched;
+uint32_t switch_result;
+
+struct randr_mode {
+       int width, height, refresh, flags;
+       struct wl_list link;
+};
+
+struct randr_output {
+       struct wl_output *output;
+       int transform;
+       char *make;
+       char *model;
+       struct wl_list modes;
+
+       struct wl_list link;
+};
+
+
+
+static void
+switch_mode_done(void *data, struct wlrandr *wlrander, uint32_t result)
+{
+       mode_switched = 1;
+       switch_result = result;
+}
+
+static const struct wlrandr_listener wlrander_listener = {
+               switch_mode_done
+};
+
+static void
+display_handle_geometry(void *data,
+                       struct wl_output *wl_output,
+                       int x,
+                       int y,
+                       int physical_width,
+                       int physical_height,
+                       int subpixel,
+                       const char *make,
+                       const char *model,
+                       int transform)
+{
+       struct randr_output *output;
+       output = wl_output_get_user_data(wl_output);
+       output->make = strdup(make);
+       output->model = strdup(model);
+       output->transform = transform;
+}
+
+static void
+display_handle_mode(void *data,
+                   struct wl_output *wl_output,
+                   uint32_t flags,
+                   int width,
+                   int height,
+                   int refresh)
+{
+       struct randr_output *output;
+       struct randr_mode *mode;
+
+       output = wl_output_get_user_data(wl_output);
+       mode = malloc(sizeof *mode);
+       mode->width = width;
+       mode->height = height;
+       mode->refresh = refresh;
+       mode->flags = flags;
+       wl_list_insert(&output->modes, &mode->link);
+}
+
+static const struct wl_output_listener output_listener = {
+       display_handle_geometry,
+       display_handle_mode
+};
+
+
+static void
+handle_global(void *data, struct wl_registry *registry,
+             uint32_t name, const char *interface, uint32_t version)
+{
+       static struct randr_output *output;
+
+       if (strcmp(interface, "wl_output") == 0) {
+               output = calloc(sizeof *output, 1);
+               output->output = wl_registry_bind(registry, name, 
&wl_output_interface, 1);
+               wl_list_init(&output->modes);
+               wl_list_insert(&output_list, &output->link);
+               wl_output_add_listener(output->output, &output_listener, 
output);
+       } else if (strcmp(interface, "wlrandr") == 0) {
+               wlRandr = wl_registry_bind(registry, name, &wlrandr_interface, 
1);
+       }
+}
+
+static void
+handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
+{
+       /* XXX: unimplemented */
+}
+
+static const struct wl_registry_listener registry_listener = {
+       handle_global,
+       handle_global_remove
+};
+
+static int
+parse_mode(const char *mode, int *w, int *h)
+{
+       /* parses a mode with the format <width>x<height> */
+       const char *ptr;
+       ptr = strchr(mode, 'x');
+       if(!ptr)
+               return -1;
+       *w = strtoul(mode, NULL, 0);
+       if(!*w || *w > 5000)
+               return -1;
+
+       ptr++;
+       if(!*ptr)
+               return -1;
+       *h = strtoul(ptr, NULL, 0);
+       if(!*h || *h > 5000)
+               return -1;
+       return 0;
+}
+
+static void
+usage(char *argv[]) {
+       fprintf(stderr, "usage: %s [options]\n", argv[0]);
+       fprintf(stderr, "  where options are:\n");
+       fprintf(stderr, "  --mode <width>x<height>\n");
+       fprintf(stderr, "  --refresh <rate> or -r <rate> or --rate <rate>\n");
+       fprintf(stderr, "  --output <output>\n");
+}
+
+static struct randr_output *
+find_output(const char *name) {
+       struct randr_output *ret;
+
+       wl_list_for_each(ret, &output_list, link) {
+               if(strcmp(ret->model, name) == 0)
+                       return ret;
+       }
+       return 0;
+}
+
+static void
+print_available_modes(struct randr_output *output) {
+       struct randr_mode *mode;
+       fprintf(stderr, "%s %s:\n", output->make, output->model);
+       wl_list_for_each(mode, &output->modes, link) {
+               fprintf(stderr, "  %s%dx%d\t%d\n", (mode->flags & 
WL_OUTPUT_MODE_CURRENT) ? "*" : "",
+                               mode->width, mode->height, mode->refresh);
+       }
+}
+
+
+int main(int argc, char *argv[])
+{
+       struct wl_display *display;
+       struct wl_registry *registry;
+       struct randr_output *output;
+       struct randr_mode *mode;
+       int mode_found;
+
+       char *mode_string= NULL;
+       char *output_name = NULL;
+       int width, height, refresh = -1;
+
+       const struct weston_option options[] = {
+               { WESTON_OPTION_STRING,  "mode", 0, &mode_string },
+               { WESTON_OPTION_STRING,  "output", 0, &output_name },
+               { WESTON_OPTION_UNSIGNED_INTEGER,  "rate", 0, &refresh },
+               { WESTON_OPTION_UNSIGNED_INTEGER,  "refresh", 0, &refresh }
+       };
+
+       if(parse_options(options, ARRAY_LENGTH(options), &argc, argv) < 0) {
+               usage(argv);
+               exit(EXIT_FAILURE);
+       }
+
+       display = wl_display_connect(NULL);
+       if (display == NULL) {
+               fprintf(stderr, "failed to create display: %m\n");
+               exit(EXIT_FAILURE);
+       }
+
+       wl_list_init(&output_list);
+       registry = wl_display_get_registry(display);
+       wl_registry_add_listener(registry, &registry_listener, NULL);
+       wl_display_dispatch(display);
+       wl_display_roundtrip(display);
+       if (wlRandr == NULL) {
+               fprintf(stderr, "display doesn't support wlRandr\n");
+               return -1;
+       }
+
+       wlrandr_add_listener(wlRandr, &wlrander_listener, wlRandr);
+
+       if(output_name) {
+               output = find_output(output_name);
+               if(!output) {
+                       fprintf(stderr, "output %s not found\n", output_name);
+                       exit(EXIT_FAILURE);
+               }
+       } else {
+               if(wl_list_length(&output_list) != 1) {
+                       fprintf(stderr, "multiple output detected, you should 
specify the "
+                                       "target output with --output 
<output>\n");
+                       exit(EXIT_FAILURE);
+               }
+
+               output = wl_container_of(output_list.next, output, link);
+       }
+
+       if(!mode_string) {
+               print_available_modes(output);
+               exit(EXIT_SUCCESS);
+       }
+
+       if(parse_mode(argv[1], &width, &height) < 0) {
+               fprintf(stderr, "invalid mode %s", mode_string);
+               usage(argv);
+               exit(EXIT_FAILURE);
+       }
+
+       mode_found = 0;
+       wl_list_for_each(mode, &output->modes, link) {
+               if(mode->width == width && mode->height == height) {
+                       if(refresh < 0 || mode->refresh == refresh) {
+                               mode_found = 1;
+                               break;
+                       }
+               }
+       }
+
+       if(!mode_found) {
+               fprintf(stderr, "mode %dx%d not available\n", width, height);
+               exit(EXIT_FAILURE);
+       }
+
+       if(mode->flags & WL_OUTPUT_MODE_CURRENT) {
+               fprintf(stderr, "mode %dx%d is already the current mode\n", 
width, height);
+               exit(0);
+       }
+
+       if(refresh < 0)
+               refresh = 0;
+       wlrandr_switch_mode(wlRandr, output->output, width, height, refresh);
+       mode_switched = 0;
+       while (!mode_switched)
+               wl_display_roundtrip(display);
+
+       switch(switch_result) {
+       case WLRANDR_SWITCH_MODE_RESULT_FAILED:
+               fprintf(stderr, "something failed in weston during mode 
switch\n");
+               break;
+       case WLRANDR_SWITCH_MODE_RESULT_NOT_AVAILABLE:
+               fprintf(stderr, "mode not available in weston\n");
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
diff --git a/protocol/Makefile.am b/protocol/Makefile.am
index 8c1803c..1454909 100644
--- a/protocol/Makefile.am
+++ b/protocol/Makefile.am
@@ -6,4 +6,5 @@ EXTRA_DIST =                                    \
        text.xml                                \
        input-method.xml                        \
        workspaces.xml                          \
-       wayland-test.xml
+       wayland-test.xml                        \
+       wlrandr.xml
diff --git a/protocol/wlrandr.xml b/protocol/wlrandr.xml
new file mode 100644
index 0000000..192ba24
--- /dev/null
+++ b/protocol/wlrandr.xml
@@ -0,0 +1,62 @@
+<protocol name="wlrandr">
+  <copyright>
+    Copyright © 2013 Hardening, [email protected]
+
+    Permission to use, copy, modify, distribute, and sell this
+    software and its documentation for any purpose is hereby granted
+    without fee, provided that the above copyright notice appear in
+    all copies and that both that copyright notice and this permission
+    notice appear in supporting documentation, and that the name of
+    the copyright holders not be used in advertising or publicity
+    pertaining to distribution of the software without specific,
+    written prior permission.  The copyright holders make no
+    representations about the suitability of this software for any
+    purpose.  It is provided "as is" without express or implied
+    warranty.
+
+    THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+    SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+    FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+    SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+    AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+    ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+    THIS SOFTWARE.
+  </copyright>
+
+
+  <interface name="wlrandr" version="1">
+    <description summary="xRandr for weston">
+    This is a port of the xRandr extension for weston
+    </description>
+  
+    <request name="switch_mode">
+      <description summary="switch mode">
+        Asks weston to switch graphical mode for the given output.
+      </description>
+    
+      <arg name="output" type="object" interface="wl_output"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+      <arg name="refresh" type="int"/>      
+    </request>
+    
+    <enum name="switch_mode_result">
+      <description summary="switch mode result">
+        The result of a switch_mode request
+      </description>
+       
+       <entry name="ok" value="0"
+               summary="the mode switch completed successfully"/>
+       <entry name="failed" value="1"
+               summary="something failed during mode switch (internal error)"/>
+       <entry name="not_available" value="2"
+               summary="the requested mode was not available"/>
+    </enum>
+    
+    <event name="done">
+       <arg name='result' type='uint'/>
+    </event>
+  </interface>
+
+</protocol>
diff --git a/src/Makefile.am b/src/Makefile.am
index 2c93a7b..2410327 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -34,6 +34,9 @@ weston_SOURCES =                              \
        input-method-server-protocol.h          \
        workspaces-protocol.c                   \
        workspaces-server-protocol.h            \
+       wlrandr.c                               \
+       wlrandr-protocol.c                      \
+       wlrandr-server-protocol.h               \
        bindings.c                              \
        animation.c                             \
        gl-renderer.h                           \
@@ -252,6 +255,8 @@ BUILT_SOURCES =                                     \
        input-method-server-protocol.h          \
        workspaces-server-protocol.h            \
        workspaces-protocol.c                   \
+       wlrandr-server-protocol.h               \
+       wlrandr-protocol.c                      \
        git-version.h
 
 CLEANFILES = $(BUILT_SOURCES)
diff --git a/src/compositor.c b/src/compositor.c
index a2860fd..c372968 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -3075,6 +3075,7 @@ weston_compositor_init(struct weston_compositor *ec,
        ec->ping_handler = NULL;
 
        screenshooter_create(ec);
+       wlrandr_create(ec);
        text_cursor_position_notifier_create(ec);
        text_backend_init(ec);
 
diff --git a/src/compositor.h b/src/compositor.h
index 4a0c1e3..3f56c73 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -775,6 +775,9 @@ tty_activate_vt(struct tty *tty, int vt);
 void
 screenshooter_create(struct weston_compositor *ec);
 
+void
+wlrandr_create(struct weston_compositor *ec);
+
 struct clipboard *
 clipboard_create(struct weston_seat *seat);
 
diff --git a/src/wlrandr.c b/src/wlrandr.c
new file mode 100644
index 0000000..a1950a2
--- /dev/null
+++ b/src/wlrandr.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright © 2013 Hardening <[email protected]>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "compositor.h"
+#include "wlrandr-server-protocol.h"
+
+struct wlrandr_impl {
+       struct wl_object base;
+       struct weston_compositor *ec;
+       struct wl_global *global;
+       struct wl_listener destroy_listener;
+};
+
+static void
+wlrandr_switch_mode(struct wl_client *client, struct wl_resource *resource,
+                           struct wl_resource *output_resource,
+                           int32_t width, int32_t height, int32_t refresh) {
+       struct weston_output *o = (struct weston_output *)output_resource->data;
+       struct weston_mode mode;
+
+       weston_log("switching to %dx%d@%d\n", width, height, refresh);
+       mode.width = width;
+       mode.height = height;
+       mode.refresh = refresh;
+
+       int ret = weston_output_switch_mode(o, &mode);
+       if(ret < 0) {
+               switch(ret) {
+               case -ENOENT:
+                       wlrandr_send_done(resource, 
WLRANDR_SWITCH_MODE_RESULT_NOT_AVAILABLE);
+                       break;
+               default:
+                       /* generic error */
+                       wlrandr_send_done(resource, 
WLRANDR_SWITCH_MODE_RESULT_FAILED);
+                       break;
+               }
+       } else {
+               wlrandr_send_done(resource, WLRANDR_SWITCH_MODE_RESULT_OK);
+       }
+}
+
+struct wlrandr_interface wlrandr_implementation = {
+       wlrandr_switch_mode
+};
+
+static void
+bind_wlrandr(struct wl_client *client,
+            void *data, uint32_t version, uint32_t id)
+{
+       wl_client_add_object(client, &wlrandr_interface, 
&wlrandr_implementation,
+                       id, data);
+}
+
+static void
+wlrandr_destroy(struct wl_listener *listener, void *data)
+{
+       struct wlrandr_impl *randr =
+               container_of(listener, struct wlrandr_impl, destroy_listener);
+
+       wl_display_remove_global(randr->ec->wl_display, randr->global);
+       free(randr);
+}
+
+
+void
+wlrandr_create(struct weston_compositor *ec)
+{
+       struct wlrandr_impl *randr;
+
+       randr = malloc(sizeof *randr);
+       if (randr == NULL)
+               return;
+
+       randr->base.interface = &wlrandr_interface;
+       randr->base.implementation = (void(**)(void))&wlrandr_implementation;
+       randr->ec = ec;
+       randr->global = wl_display_add_global(ec->wl_display, 
&wlrandr_interface,
+                                               randr, bind_wlrandr);
+
+       randr->destroy_listener.notify = wlrandr_destroy;
+       wl_signal_add(&ec->destroy_signal, &randr->destroy_listener);
+}
-- 
1.7.10.4

_______________________________________________
wayland-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to