1 /* 2 * The MIT License (MIT) 3 * 4 * Copyright (c) 2020 Scott Moreau 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 */ 24 25 #include <wayfire/core.hpp> 26 #include <wayfire/view.hpp> 27 #include <wayfire/plugin.hpp> 28 #include <wayfire/output.hpp> 29 #include <wayfire/render-manager.hpp> 30 #include "wayfire/view-transform.hpp" 31 #include "wayfire/workspace-manager.hpp" 32 33 34 class winzoom_t : public wf::view_2D 35 { 36 wf::option_wrapper_t<bool> nearest_filtering{"winzoom/nearest_filtering"}; 37 wayfire_view view; 38 39 wf::config::option_base_t::updated_callback_t filtering_changed = [=] () __anon5d343bc20102() 40 { 41 view->damage(); 42 }; 43 44 public: winzoom_t(wayfire_view view)45 winzoom_t(wayfire_view view) : wf::view_2D(view) 46 { 47 nearest_filtering.set_callback(filtering_changed); 48 this->view = view; 49 } 50 ~winzoom_t()51 ~winzoom_t() 52 {} 53 render_with_damage(wf::texture_t src_tex,wlr_box src_box,const wf::region_t & damage,const wf::framebuffer_t & target_fb)54 void render_with_damage(wf::texture_t src_tex, wlr_box src_box, 55 const wf::region_t& damage, const wf::framebuffer_t& target_fb) override 56 { 57 GL_CALL(glBindTexture(GL_TEXTURE_2D, src_tex.tex_id)); 58 GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, 59 nearest_filtering ? GL_NEAREST : GL_LINEAR)); 60 GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 61 nearest_filtering ? GL_NEAREST : GL_LINEAR)); 62 wf::view_transformer_t::render_with_damage(src_tex, src_box, damage, 63 target_fb); 64 } 65 }; 66 67 class wayfire_winzoom : public wf::plugin_interface_t 68 { 69 wf::option_wrapper_t<wf::activatorbinding_t> inc_x_binding{ 70 "winzoom/inc_x_binding"}; 71 wf::option_wrapper_t<wf::activatorbinding_t> dec_x_binding{ 72 "winzoom/dec_x_binding"}; 73 wf::option_wrapper_t<wf::activatorbinding_t> inc_y_binding{ 74 "winzoom/inc_y_binding"}; 75 wf::option_wrapper_t<wf::activatorbinding_t> dec_y_binding{ 76 "winzoom/dec_y_binding"}; 77 wf::option_wrapper_t<bool> preserve_aspect{"winzoom/preserve_aspect"}; 78 wf::option_wrapper_t<wf::keybinding_t> modifier{"winzoom/modifier"}; 79 wf::option_wrapper_t<double> zoom_step{"winzoom/zoom_step"}; 80 81 public: init()82 void init() override 83 { 84 grab_interface->name = "winzoom"; 85 grab_interface->capabilities = 0; 86 87 output->add_axis(modifier, &axis_cb); 88 output->add_activator(inc_x_binding, &on_inc_x); 89 output->add_activator(dec_x_binding, &on_dec_x); 90 output->add_activator(inc_y_binding, &on_inc_y); 91 output->add_activator(dec_y_binding, &on_dec_y); 92 } 93 update_winzoom(wayfire_view view,wf::point_t delta)94 bool update_winzoom(wayfire_view view, wf::point_t delta) 95 { 96 winzoom_t *transformer; 97 wf::pointf_t zoom; 98 99 if (!view) 100 { 101 return false; 102 } 103 104 if (!output->activate_plugin(grab_interface)) 105 { 106 return false; 107 } 108 109 output->deactivate_plugin(grab_interface); 110 111 auto layer = output->workspace->get_view_layer(view); 112 113 if (layer & (wf::LAYER_BACKGROUND | wf::LAYER_TOP)) 114 { 115 return false; 116 } 117 118 if (view->role == wf::VIEW_ROLE_DESKTOP_ENVIRONMENT) 119 { 120 return false; 121 } 122 123 if (!view->get_transformer("winzoom")) 124 { 125 view->add_transformer(std::make_unique<winzoom_t>(view), "winzoom"); 126 } 127 128 transformer = 129 dynamic_cast<winzoom_t*>(view->get_transformer("winzoom").get()); 130 131 zoom.x = transformer->scale_x; 132 zoom.y = transformer->scale_y; 133 134 if (preserve_aspect) 135 { 136 if ((delta.x <= 0) && (delta.y <= 0)) 137 { 138 delta.x = delta.y = std::min(delta.x, delta.y); 139 } 140 141 if ((delta.x >= 0) && (delta.y >= 0)) 142 { 143 delta.x = delta.y = std::max(delta.x, delta.y); 144 } 145 } 146 147 zoom.x += zoom_step * delta.x; 148 zoom.y += zoom_step * delta.y; 149 150 zoom.x = std::max(1.0, zoom.x); 151 zoom.y = std::max(1.0, zoom.y); 152 153 if ((zoom.x == 1.0) && (zoom.y == 1.0)) 154 { 155 view->pop_transformer("winzoom"); 156 return true; 157 } 158 159 if (transformer->scale_x != zoom.x) 160 { 161 transformer->scale_x = zoom.x; 162 } 163 164 if (transformer->scale_y != zoom.y) 165 { 166 transformer->scale_y = zoom.y; 167 } 168 169 output->render->damage_whole(); 170 171 return true; 172 } 173 174 wf::activator_callback on_inc_x = [=] (auto) __anon5d343bc20202(auto) 175 { 176 auto view = output->get_active_view(); 177 return update_winzoom(view, wf::point_t{1, 0}); 178 }; 179 180 wf::activator_callback on_dec_x = [=] (auto) __anon5d343bc20302(auto) 181 { 182 auto view = output->get_active_view(); 183 return update_winzoom(view, wf::point_t{-1, 0}); 184 }; 185 186 wf::activator_callback on_inc_y = [=] (auto) __anon5d343bc20402(auto) 187 { 188 auto view = output->get_active_view(); 189 return update_winzoom(view, wf::point_t{0, 1}); 190 }; 191 192 wf::activator_callback on_dec_y = [=] (auto) __anon5d343bc20502(auto) 193 { 194 auto view = output->get_active_view(); 195 return update_winzoom(view, wf::point_t{0, -1}); 196 }; 197 198 wf::axis_callback axis_cb = [=] (wlr_event_pointer_axis *ev) __anon5d343bc20602(wlr_event_pointer_axis *ev) 199 { 200 auto view = wf::get_core().get_cursor_focus_view(); 201 if (ev->orientation == WLR_AXIS_ORIENTATION_VERTICAL) 202 { 203 auto delta = (int)-std::clamp(ev->delta, -1.0, 1.0); 204 return update_winzoom(view, wf::point_t{delta, delta}); 205 } 206 207 return false; 208 }; 209 fini()210 void fini() override 211 { 212 for (auto& view : output->workspace->get_views_in_layer(wf::ALL_LAYERS)) 213 { 214 if (view->get_transformer("winzoom")) 215 { 216 view->pop_transformer("winzoom"); 217 } 218 } 219 220 output->rem_binding(&axis_cb); 221 output->rem_binding(&on_inc_x); 222 output->rem_binding(&on_dec_x); 223 output->rem_binding(&on_inc_y); 224 output->rem_binding(&on_dec_y); 225 } 226 }; 227 228 DECLARE_WAYFIRE_PLUGIN(wayfire_winzoom); 229