<br><br><div class="gmail_quote">2012/2/21 Kristian Høgsberg <span dir="ltr">&lt;<a href="mailto:krh@bitplanet.net">krh@bitplanet.net</a>&gt;</span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im">On Mon, Feb 20, 2012 at 11:56 PM, Scott Moreau &lt;<a href="mailto:oreaus@gmail.com">oreaus@gmail.com</a>&gt; wrote:<br>
&gt; Implement a camera/modelview matrix for transforms to simulate camera movement.<br>
&gt; Ideally, we would want to use &lt;modifier&gt;+Scroll but that will have to wait<br>
&gt; for axis events. For now we use keyboard grabs. Zoom in/out with Super+Up/Down.<br>
&gt; Zoom area follows mouse pointer.<br>
<br>
</div>Very cool!  I like it, but there&#39;s a few comments below.<br>
<br>
thanks,<br>
Kristian<br>
<div><div class="h5"><br>
&gt; ---<br>
&gt;  src/compositor.c |   41 +++++++++++++++++++++++-<br>
&gt;  src/compositor.h |   12 +++++++<br>
&gt;  src/shell.c      |   91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++<br>
&gt;  3 files changed, 143 insertions(+), 1 deletions(-)<br>
&gt;<br>
&gt; diff --git a/src/compositor.c b/src/compositor.c<br>
&gt; index 8339e6c..ccbccd4 100644<br>
&gt; --- a/src/compositor.c<br>
&gt; +++ b/src/compositor.c<br>
&gt; @@ -925,6 +925,7 @@ weston_output_repaint(struct weston_output *output, int msecs)<br>
&gt;        struct weston_surface *es;<br>
&gt;        struct weston_animation *animation, *next;<br>
&gt;        struct weston_frame_callback *cb, *cnext;<br>
&gt; +       struct weston_matrix modelview;<br>
&gt;        pixman_region32_t opaque, new_damage, total_damage,<br>
&gt;                overlap, surface_overlap;<br>
&gt;        int32_t width, height;<br>
&gt; @@ -937,6 +938,12 @@ weston_output_repaint(struct weston_output *output, int msecs)<br>
&gt;                output-&gt;border.top + output-&gt;border.bottom;<br>
&gt;        glViewport(0, 0, width, height);<br>
&gt;<br>
&gt; +       weston_matrix_init(&amp;output-&gt;camera_matrix);<br>
&gt; +       weston_matrix_translate(&amp;output-&gt;camera_matrix,<br>
&gt; +                                               output-&gt;zoom.trans_x,<br>
&gt; +                                               output-&gt;zoom.trans_y, 0);<br>
&gt; +       weston_matrix_invert(&amp;modelview, &amp;output-&gt;camera_matrix);<br>
&gt; +<br>
<br>
</div></div>I think we want to move the output-&gt;matrix computation out in a<br>
weston_output_update_matrix() functions and then just roll the zoom<br>
math into that.  Then in weston_output_move() or the zoom functions,<br>
when we update the output transform, we just mark it dirty and<br>
recompute it in weston_output_repaint().<br></blockquote><div><br>Yes, this sounds like it would be more versatile.<br><br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

<div class="im"><br>
&gt;        pixman_region32_init(&amp;new_damage);<br>
&gt;        pixman_region32_init(&amp;opaque);<br>
&gt;        pixman_region32_init(&amp;overlap);<br>
&gt; @@ -953,6 +960,9 @@ weston_output_repaint(struct weston_output *output, int msecs)<br>
&gt;                pixman_region32_fini(&amp;surface_overlap);<br>
&gt;                pixman_region32_union(&amp;overlap, &amp;overlap,<br>
&gt;                                      &amp;es-&gt;transform.boundingbox);<br>
&gt; +               glUniform1f(es-&gt;shader-&gt;zoom_uniform, output-&gt;zoom.level);<br>
&gt; +               glUniformMatrix4fv(es-&gt;shader-&gt;modelview_uniform,<br>
&gt; +                                  1, GL_FALSE, modelview.d);<br>
<br>
</div>Need to do this in weston_surface_draw so we update the right shader<br>
uniform, but if we roll the zoom transform into output-&gt;matrix as<br>
described above that will happen automatically.<br></blockquote><div><br>Noted.<br><br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div class="im"><br>
&gt;        }<br>
&gt;<br>
&gt;        weston_output_set_cursor(output, ec-&gt;input_device);<br>
&gt; @@ -1322,6 +1332,9 @@ notify_motion(struct wl_input_device *device, uint32_t time, int x, int y)<br>
&gt;                        max_x = output-&gt;x + output-&gt;current-&gt;width;<br>
&gt;                if (output-&gt;y + output-&gt;current-&gt;height &gt; max_y)<br>
&gt;                        max_y = output-&gt;y + output-&gt;current-&gt;height;<br>
&gt; +               if (output-&gt;zoom.active &amp;&amp;<br>
&gt; +                   pixman_region32_contains_point(&amp;output-&gt;region, x, y, NULL))<br>
&gt; +                       zoom_update(output, x, y);<br>
<br>
</div>There&#39;s an edge case here (literally!) since if the pointer is on the<br>
screen edge, the zoom position doesn&#39;t update.  If I move along the<br>
edge, the view doesn&#39;t change. Only when I move it into the screen,<br>
away from the edge does the position update.<br></blockquote><div><br>Admittedly, I haven&#39;t tested it outside of X. I will have a look into it.<br><br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

<div class="im"><br>
&gt;        }<br>
&gt;<br>
&gt;        if (!x_valid) {<br>
&gt; @@ -1850,12 +1863,14 @@ bind_output(struct wl_client *client,<br>
&gt;<br>
&gt;  static const char vertex_shader[] =<br>
&gt;        &quot;uniform mat4 proj;\n&quot;<br>
&gt; +       &quot;uniform mat4 modelview;\n&quot;<br>
&gt; +       &quot;uniform float zoom;\n&quot;<br>
&gt;        &quot;attribute vec2 position;\n&quot;<br>
&gt;        &quot;attribute vec2 texcoord;\n&quot;<br>
&gt;        &quot;varying vec2 v_texcoord;\n&quot;<br>
&gt;        &quot;void main()\n&quot;<br>
&gt;        &quot;{\n&quot;<br>
&gt; -       &quot;   gl_Position = proj * vec4(position, 0.0, 1.0);\n&quot;<br>
&gt; +       &quot;   gl_Position = proj * (modelview * vec4(position, 0.0, zoom));\n&quot;<br>
&gt;        &quot;   v_texcoord = texcoord;\n&quot;<br>
&gt;        &quot;}\n&quot;;<br>
<br>
</div>Again, if we roll the zoom into the output matrix we don&#39;t need this.<br></blockquote><div><br>Ok.<br><br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

<div class="im"><br>
&gt; @@ -1929,6 +1944,8 @@ weston_shader_init(struct weston_shader *shader,<br>
&gt;        }<br>
&gt;<br>
&gt;        shader-&gt;proj_uniform = glGetUniformLocation(shader-&gt;program, &quot;proj&quot;);<br>
&gt; +       shader-&gt;modelview_uniform = glGetUniformLocation(shader-&gt;program, &quot;modelview&quot;);<br>
&gt; +       shader-&gt;zoom_uniform = glGetUniformLocation(shader-&gt;program, &quot;zoom&quot;);<br>
&gt;        shader-&gt;tex_uniform = glGetUniformLocation(shader-&gt;program, &quot;tex&quot;);<br>
&gt;        shader-&gt;alpha_uniform = glGetUniformLocation(shader-&gt;program, &quot;alpha&quot;);<br>
&gt;        shader-&gt;color_uniform = glGetUniformLocation(shader-&gt;program, &quot;color&quot;);<br>
&gt; @@ -1946,6 +1963,21 @@ weston_output_destroy(struct weston_output *output)<br>
&gt;  }<br>
&gt;<br>
&gt;  WL_EXPORT void<br>
&gt; +zoom_update(struct weston_output *output, int x, int y)<br>
&gt; +{<br>
&gt; +       if (output-&gt;zoom.level &lt;= 0)<br>
&gt; +               return;<br>
&gt; +<br>
&gt; +       float ratio = (1 / output-&gt;zoom.level) - 1;<br>
&gt; +<br>
&gt; +       output-&gt;zoom.trans_x = (output-&gt;mm_width * ratio) *<br>
&gt; +                                       ((float)x / output-&gt;mm_width);<br>
&gt; +       output-&gt;zoom.trans_y = (output-&gt;mm_height * ratio) *<br>
&gt; +                                       ((float)y  / output-&gt;mm_height);<br>
&gt; +       weston_output_damage(output);<br>
&gt; +}<br>
<br>
</div>output-&gt;mm_width is the physical width of the display (in millimeter),<br>
not the number of pixels.  Use output-&gt;current-&gt;width.</blockquote><div><br>Ah, I did not realize this<br> <br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
 And this
should be in the weston_output_matrix_update() function mentioned<br>
above.<br></blockquote><div><br>Right.<br> </div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div><div class="h5"><br>
&gt; +WL_EXPORT void<br>
&gt;  weston_output_move(struct weston_output *output, int x, int y)<br>
&gt;  {<br>
&gt;        int flip;<br>
&gt; @@ -1985,6 +2017,13 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c,<br>
&gt;        output-&gt;mm_width = width;<br>
&gt;        output-&gt;mm_height = height;<br>
&gt;<br>
&gt; +       output-&gt;zoom.active = 0;<br>
&gt; +       output-&gt;zoom.level = 1.0;<br>
&gt; +       output-&gt;zoom.trans_x = 0.0;<br>
&gt; +       output-&gt;zoom.trans_y = 0.0;<br>
&gt; +<br>
&gt; +       weston_matrix_init(&amp;output-&gt;camera_matrix);<br>
&gt; +<br>
&gt;        output-&gt;flags = flags;<br>
&gt;        weston_output_move(output, x, y);<br>
&gt;<br>
&gt; diff --git a/src/compositor.h b/src/compositor.h<br>
&gt; index 4c82e79..66ec688 100644<br>
&gt; --- a/src/compositor.h<br>
&gt; +++ b/src/compositor.h<br>
&gt; @@ -54,10 +54,17 @@ struct weston_border {<br>
&gt;        int32_t left, right, top, bottom;<br>
&gt;  };<br>
&gt;<br>
&gt; +struct weston_output_zoom {<br>
&gt; +       int active;<br>
&gt; +       float level;<br>
&gt; +       int trans_x, trans_y;<br>
&gt; +};<br>
&gt; +<br>
&gt;  struct weston_output {<br>
&gt;        struct wl_list link;<br>
&gt;        struct weston_compositor *compositor;<br>
&gt;        struct weston_matrix matrix;<br>
&gt; +       struct weston_matrix camera_matrix;<br>
&gt;        struct wl_list frame_callback_list;<br>
&gt;        int32_t x, y, mm_width, mm_height;<br>
&gt;        struct weston_border border;<br>
&gt; @@ -66,6 +73,7 @@ struct weston_output {<br>
&gt;        uint32_t flags;<br>
&gt;        int repaint_needed;<br>
&gt;        int repaint_scheduled;<br>
&gt; +       struct weston_output_zoom zoom;<br>
&gt;<br>
&gt;        char *make, *model;<br>
&gt;        uint32_t subpixel;<br>
&gt; @@ -100,6 +108,8 @@ struct weston_shader {<br>
&gt;        GLuint program;<br>
&gt;        GLuint vertex_shader, fragment_shader;<br>
&gt;        GLint proj_uniform;<br>
&gt; +       GLint modelview_uniform;<br>
&gt; +       GLint zoom_uniform;<br>
&gt;        GLint tex_uniform;<br>
&gt;        GLint alpha_uniform;<br>
&gt;        GLint color_uniform;<br>
&gt; @@ -414,6 +424,8 @@ weston_compositor_init(struct weston_compositor *ec, struct wl_display *display)<br>
&gt;  void<br>
&gt;  weston_compositor_shutdown(struct weston_compositor *ec);<br>
&gt;  void<br>
&gt; +zoom_update(struct weston_output *output, int x, int y);<br>
&gt; +void<br>
&gt;  weston_output_move(struct weston_output *output, int x, int y);<br>
&gt;  void<br>
&gt;  weston_output_init(struct weston_output *output, struct weston_compositor *c,<br>
&gt; diff --git a/src/shell.c b/src/shell.c<br>
&gt; index fa165e2..ee406f0 100644<br>
&gt; --- a/src/shell.c<br>
&gt; +++ b/src/shell.c<br>
&gt; @@ -113,6 +113,11 @@ struct shell_surface {<br>
&gt;        struct wl_list link;<br>
&gt;  };<br>
&gt;<br>
&gt; +struct weston_zoom_grab {<br>
&gt; +       struct wl_keyboard_grab grab;<br>
&gt; +       uint32_t key;<br>
&gt; +};<br>
&gt; +<br>
&gt;  struct weston_move_grab {<br>
&gt;        struct wl_pointer_grab grab;<br>
&gt;        struct weston_surface *surface;<br>
&gt; @@ -1035,6 +1040,88 @@ resize_binding(struct wl_input_device *device, uint32_t time,<br>
&gt;  }<br>
&gt;<br>
&gt;  static void<br>
&gt; +zoom_grab_key(struct wl_keyboard_grab *grab,<br>
&gt; +                uint32_t time, uint32_t key, int32_t state)<br>
&gt; +{<br>
&gt; +       struct weston_zoom_grab *zoom;<br>
&gt; +       zoom = container_of(grab, struct weston_zoom_grab, grab);<br>
&gt; +<br>
&gt; +       if (state == 0) {<br>
&gt; +               wl_input_device_end_keyboard_grab(grab-&gt;input_device, time);<br>
&gt; +               free(zoom);<br>
&gt; +       }<br>
&gt; +}<br>
&gt; +<br>
&gt; +static const struct wl_keyboard_grab_interface zoom_grab_interface = {<br>
&gt; +       zoom_grab_key,<br>
&gt; +};<br>
&gt; +<br>
&gt; +static void<br>
&gt; +zoom_in_binding(struct wl_input_device *device, uint32_t time,<br>
&gt; +              uint32_t key, uint32_t button, uint32_t state, void *data)<br>
&gt; +{<br>
&gt; +       struct weston_input_device *wd = (struct weston_input_device *) device;<br>
&gt; +       struct weston_compositor *compositor = wd-&gt;compositor;<br>
&gt; +       struct weston_output *output;<br>
&gt; +       struct weston_zoom_grab *zoom;<br>
&gt; +<br>
&gt; +       zoom = malloc(sizeof *zoom);<br>
&gt; +       if (!zoom)<br>
&gt; +               return;<br>
&gt; +<br>
&gt; +       zoom-&gt;grab.interface = &amp;zoom_grab_interface;<br>
&gt; +<br>
&gt; +       wl_input_device_start_keyboard_grab(&amp;wd-&gt;input_device, &amp;zoom-&gt;grab, time);<br>
<br>
</div></div>Why do you use a key grab here?  Oh, it&#39;s to avoid delivering the<br>
event right?  I think  we just need to make bindings swallow the event<br>
(key press and release for the key in question, for buttons too).</blockquote><div><br>Indeed.<br> <br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
The
grab method you&#39;re using breaks if somebody presses and then releases<br>
another key or the super key first.<br></blockquote><div><br>Yes, I realize this. I just wanted to make sure there was no chance of not freeing<br>allocated memory.<br> </div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

<br>
Oh, as a feature request, could we make shift+super do integer<br>
scaling?  As it is, I have to press 10 times to get to double size,<br>
triple size isn&#39;t possible, and 10 more times to do 4 times zoom.</blockquote><div><br>Absolutely.<br> </div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
 We may also want GL_LINEAR filtering when we&#39;re zoomed to a non-integer<br>
multiple.<br></blockquote><div><br>Yes, indeed.<br> </div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div><div class="h5"><br>
&gt; +       wl_list_for_each(output, &amp;compositor-&gt;output_list, link) {<br>
&gt; +               if (pixman_region32_contains_point(&amp;output-&gt;region,<br>
&gt; +                                               device-&gt;x, device-&gt;y, NULL)) {<br>
&gt; +                       output-&gt;zoom.active = 1;<br>
&gt; +                       output-&gt;zoom.level -= 0.05;<br>
&gt; +                       if (output-&gt;zoom.level &gt; 1.0)<br>
&gt; +                               output-&gt;zoom.level = 1.0;<br>
&gt; +                       if (output-&gt;zoom.level &lt; 0.0)<br>
&gt; +                               output-&gt;zoom.level = 0.05;<br>
&gt; +<br>
&gt; +                       zoom_update(output, device-&gt;x, device-&gt;y);<br>
&gt; +               }<br>
&gt; +       }<br>
&gt; +}<br>
&gt; +<br>
&gt; +static void<br>
&gt; +zoom_out_binding(struct wl_input_device *device, uint32_t time,<br>
&gt; +              uint32_t key, uint32_t button, uint32_t state, void *data)<br>
&gt; +{<br>
&gt; +       struct weston_input_device *wd = (struct weston_input_device *) device;<br>
&gt; +       struct weston_compositor *compositor = wd-&gt;compositor;<br>
&gt; +       struct weston_output *output;<br>
&gt; +       struct weston_zoom_grab *zoom;<br>
&gt; +<br>
&gt; +       zoom = malloc(sizeof *zoom);<br>
&gt; +       if (!zoom)<br>
&gt; +               return;<br>
&gt; +<br>
&gt; +       zoom-&gt;grab.interface = &amp;zoom_grab_interface;<br>
&gt; +<br>
&gt; +       wl_input_device_start_keyboard_grab(&amp;wd-&gt;input_device, &amp;zoom-&gt;grab, time);<br>
&gt; +<br>
&gt; +       wl_list_for_each(output, &amp;compositor-&gt;output_list, link) {<br>
&gt; +               if (pixman_region32_contains_point(&amp;output-&gt;region,<br>
&gt; +                                               device-&gt;x, device-&gt;y, NULL)) {<br>
&gt; +                       output-&gt;zoom.level += 0.05;<br>
&gt; +                       if (output-&gt;zoom.level &gt; 1.0)<br>
&gt; +                               output-&gt;zoom.level = 1.0;<br>
&gt; +                       if (output-&gt;zoom.level &lt; 0.0) {<br>
&gt; +                               output-&gt;zoom.active = 0;<br>
&gt; +                               output-&gt;zoom.level = 0.0;<br>
&gt; +                       }<br>
&gt; +<br>
&gt; +                       zoom_update(output, device-&gt;x, device-&gt;y);<br>
&gt; +               }<br>
&gt; +       }<br>
&gt; +}<br>
&gt; +<br>
&gt; +static void<br>
&gt;  terminate_binding(struct wl_input_device *device, uint32_t time,<br>
&gt;                  uint32_t key, uint32_t button, uint32_t state, void *data)<br>
&gt;  {<br>
&gt; @@ -1827,6 +1914,10 @@ shell_init(struct weston_compositor *ec)<br>
&gt;                                    move_binding, shell);<br>
&gt;        weston_compositor_add_binding(ec, 0, BTN_MIDDLE, MODIFIER_SUPER,<br>
&gt;                                    resize_binding, shell);<br>
&gt; +       weston_compositor_add_binding(ec, KEY_UP, 0, MODIFIER_SUPER,<br>
&gt; +                                   zoom_in_binding, shell);<br>
&gt; +       weston_compositor_add_binding(ec, KEY_DOWN, 0, MODIFIER_SUPER,<br>
&gt; +                                   zoom_out_binding, shell);<br>
&gt;        weston_compositor_add_binding(ec, KEY_BACKSPACE, 0,<br>
&gt;                                    MODIFIER_CTRL | MODIFIER_ALT,<br>
&gt;                                    terminate_binding, ec);<br>
&gt; --<br>
&gt; 1.7.4.1<br>
&gt;<br>
</div></div>&gt; _______________________________________________<br>
&gt; wayland-devel mailing list<br>
&gt; <a href="mailto:wayland-devel@lists.freedesktop.org">wayland-devel@lists.freedesktop.org</a><br>
&gt; <a href="http://lists.freedesktop.org/mailman/listinfo/wayland-devel" target="_blank">http://lists.freedesktop.org/mailman/listinfo/wayland-devel</a><br>
</blockquote></div><br><br>Thanks for your input. I will work on a v3 patch now.<br><br><br>Cheers,<br><br>Scott<br>