commands.c (8326B)
1 /* Copyright 2011, 2012, 2014 Bert Muennich 2 * 3 * This file is part of sxiv. 4 * 5 * sxiv is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published 7 * by the Free Software Foundation; either version 2 of the License, 8 * or (at your option) any later version. 9 * 10 * sxiv is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with sxiv. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include "sxiv.h" 20 #define _IMAGE_CONFIG 21 #include "config.h" 22 23 #include <stdlib.h> 24 #include <string.h> 25 #include <unistd.h> 26 #include <sys/wait.h> 27 28 void remove_file(int, bool); 29 void load_image(int); 30 bool mark_image(int, bool); 31 void close_info(void); 32 void open_info(void); 33 int ptr_third_x(void); 34 void redraw(void); 35 void reset_cursor(void); 36 void animate(void); 37 void slideshow(void); 38 void set_timeout(timeout_f, int, bool); 39 void reset_timeout(timeout_f); 40 41 extern appmode_t mode; 42 extern img_t img; 43 extern tns_t tns; 44 extern win_t win; 45 46 extern fileinfo_t *files; 47 extern int filecnt, fileidx; 48 extern int alternate; 49 extern int markcnt; 50 extern int markidx; 51 52 extern int prefix; 53 extern bool extprefix; 54 55 bool cg_quit(arg_t _) 56 { 57 unsigned int i; 58 59 if (options->to_stdout && markcnt > 0) { 60 for (i = 0; i < filecnt; i++) { 61 if (files[i].flags & FF_MARK) 62 printf("%s\n", files[i].name); 63 } 64 } 65 exit(EXIT_SUCCESS); 66 } 67 68 bool cg_switch_mode(arg_t _) 69 { 70 if (mode == MODE_IMAGE) { 71 if (tns.thumbs == NULL) 72 tns_init(&tns, files, &filecnt, &fileidx, &win); 73 img_close(&img, false); 74 reset_timeout(reset_cursor); 75 if (img.ss.on) { 76 img.ss.on = false; 77 reset_timeout(slideshow); 78 } 79 tns.dirty = true; 80 mode = MODE_THUMB; 81 } else { 82 load_image(fileidx); 83 mode = MODE_IMAGE; 84 } 85 return true; 86 } 87 88 bool cg_toggle_fullscreen(arg_t _) 89 { 90 win_toggle_fullscreen(&win); 91 /* redraw after next ConfigureNotify event */ 92 set_timeout(redraw, TO_REDRAW_RESIZE, false); 93 if (mode == MODE_IMAGE) 94 img.checkpan = img.dirty = true; 95 else 96 tns.dirty = true; 97 return false; 98 } 99 100 bool cg_toggle_bar(arg_t _) 101 { 102 win_toggle_bar(&win); 103 if (mode == MODE_IMAGE) { 104 if (win.bar.h > 0) 105 open_info(); 106 else 107 close_info(); 108 img.checkpan = img.dirty = true; 109 } else { 110 tns.dirty = true; 111 } 112 return true; 113 } 114 115 bool cg_prefix_external(arg_t _) 116 { 117 extprefix = true; 118 return false; 119 } 120 121 bool cg_reload_image(arg_t _) 122 { 123 if (mode == MODE_IMAGE) { 124 load_image(fileidx); 125 } else { 126 win_set_cursor(&win, CURSOR_WATCH); 127 if (!tns_load(&tns, fileidx, true, false)) { 128 remove_file(fileidx, false); 129 tns.dirty = true; 130 } 131 } 132 return true; 133 } 134 135 bool cg_remove_image(arg_t _) 136 { 137 remove_file(fileidx, true); 138 if (mode == MODE_IMAGE) 139 load_image(fileidx); 140 else 141 tns.dirty = true; 142 return true; 143 } 144 145 bool cg_first(arg_t _) 146 { 147 if (mode == MODE_IMAGE && fileidx != 0) { 148 load_image(0); 149 return true; 150 } else if (mode == MODE_THUMB && fileidx != 0) { 151 fileidx = 0; 152 tns.dirty = true; 153 return true; 154 } else { 155 return false; 156 } 157 } 158 159 bool cg_n_or_last(arg_t _) 160 { 161 int n = prefix != 0 && prefix - 1 < filecnt ? prefix - 1 : filecnt - 1; 162 163 if (mode == MODE_IMAGE && fileidx != n) { 164 load_image(n); 165 return true; 166 } else if (mode == MODE_THUMB && fileidx != n) { 167 fileidx = n; 168 tns.dirty = true; 169 return true; 170 } else { 171 return false; 172 } 173 } 174 175 bool cg_scroll_screen(arg_t dir) 176 { 177 if (mode == MODE_IMAGE) 178 return img_pan(&img, dir, -1); 179 else 180 return tns_scroll(&tns, dir, true); 181 } 182 183 bool cg_zoom(arg_t d) 184 { 185 if (mode == MODE_THUMB) 186 return tns_zoom(&tns, d); 187 else if (d > 0) 188 return img_zoom_in(&img); 189 else if (d < 0) 190 return img_zoom_out(&img); 191 else 192 return false; 193 } 194 195 bool cg_toggle_image_mark(arg_t _) 196 { 197 return mark_image(fileidx, !(files[fileidx].flags & FF_MARK)); 198 } 199 200 bool cg_reverse_marks(arg_t _) 201 { 202 int i; 203 204 for (i = 0; i < filecnt; i++) { 205 files[i].flags ^= FF_MARK; 206 markcnt += files[i].flags & FF_MARK ? 1 : -1; 207 } 208 if (mode == MODE_THUMB) 209 tns.dirty = true; 210 return true; 211 } 212 213 bool cg_mark_range(arg_t _) 214 { 215 int d = markidx < fileidx ? 1 : -1, end, i; 216 bool dirty = false, on = !!(files[markidx].flags & FF_MARK); 217 218 for (i = markidx + d, end = fileidx + d; i != end; i += d) 219 dirty |= mark_image(i, on); 220 return dirty; 221 } 222 223 bool cg_unmark_all(arg_t _) 224 { 225 int i; 226 227 for (i = 0; i < filecnt; i++) 228 files[i].flags &= ~FF_MARK; 229 markcnt = 0; 230 if (mode == MODE_THUMB) 231 tns.dirty = true; 232 return true; 233 } 234 235 bool cg_navigate_marked(arg_t n) 236 { 237 int d, i; 238 int new = fileidx; 239 240 if (prefix > 0) 241 n *= prefix; 242 d = n > 0 ? 1 : -1; 243 for (i = fileidx + d; n != 0 && i >= 0 && i < filecnt; i += d) { 244 if (files[i].flags & FF_MARK) { 245 n -= d; 246 new = i; 247 } 248 } 249 if (new != fileidx) { 250 if (mode == MODE_IMAGE) { 251 load_image(new); 252 } else { 253 fileidx = new; 254 tns.dirty = true; 255 } 256 return true; 257 } else { 258 return false; 259 } 260 } 261 262 bool cg_change_gamma(arg_t d) 263 { 264 if (img_change_gamma(&img, d * (prefix > 0 ? prefix : 1))) { 265 if (mode == MODE_THUMB) 266 tns.dirty = true; 267 return true; 268 } else { 269 return false; 270 } 271 } 272 273 bool ci_navigate(arg_t n) 274 { 275 if (prefix > 0) 276 n *= prefix; 277 n += fileidx; 278 if (n < 0) 279 n = 0; 280 if (n >= filecnt) 281 n = filecnt - 1; 282 283 if (n != fileidx) { 284 load_image(n); 285 return true; 286 } else { 287 return false; 288 } 289 } 290 291 bool ci_cursor_navigate(arg_t _) 292 { 293 return ci_navigate(ptr_third_x() - 1); 294 } 295 296 bool ci_alternate(arg_t _) 297 { 298 load_image(alternate); 299 return true; 300 } 301 302 bool ci_navigate_frame(arg_t d) 303 { 304 if (prefix > 0) 305 d *= prefix; 306 return !img.multi.animate && img_frame_navigate(&img, d); 307 } 308 309 bool ci_toggle_animation(arg_t _) 310 { 311 bool dirty = false; 312 313 if (img.multi.cnt > 0) { 314 img.multi.animate = !img.multi.animate; 315 if (img.multi.animate) { 316 dirty = img_frame_animate(&img); 317 set_timeout(animate, img.multi.frames[img.multi.sel].delay, true); 318 } else { 319 reset_timeout(animate); 320 } 321 } 322 return dirty; 323 } 324 325 bool ci_scroll(arg_t dir) 326 { 327 return img_pan(&img, dir, prefix); 328 } 329 330 bool ci_scroll_to_edge(arg_t dir) 331 { 332 return img_pan_edge(&img, dir); 333 } 334 335 bool ci_drag(arg_t mode) 336 { 337 int x, y, ox, oy; 338 float px, py; 339 XEvent e; 340 341 if ((int)(img.w * img.zoom) <= win.w && (int)(img.h * img.zoom) <= win.h) 342 return false; 343 344 win_set_cursor(&win, CURSOR_DRAG); 345 346 win_cursor_pos(&win, &x, &y); 347 ox = x; 348 oy = y; 349 350 for (;;) { 351 if (mode == DRAG_ABSOLUTE) { 352 px = MIN(MAX(0.0, x - win.w*0.1), win.w*0.8) / (win.w*0.8) 353 * (win.w - img.w * img.zoom); 354 py = MIN(MAX(0.0, y - win.h*0.1), win.h*0.8) / (win.h*0.8) 355 * (win.h - img.h * img.zoom); 356 } else { 357 px = img.x + x - ox; 358 py = img.y + y - oy; 359 } 360 361 if (img_pos(&img, px, py)) { 362 img_render(&img); 363 win_draw(&win); 364 } 365 XMaskEvent(win.env.dpy, 366 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e); 367 if (e.type == ButtonPress || e.type == ButtonRelease) 368 break; 369 while (XCheckTypedEvent(win.env.dpy, MotionNotify, &e)); 370 ox = x; 371 oy = y; 372 x = e.xmotion.x; 373 y = e.xmotion.y; 374 } 375 set_timeout(reset_cursor, TO_CURSOR_HIDE, true); 376 reset_cursor(); 377 378 return true; 379 } 380 381 bool ci_set_zoom(arg_t zl) 382 { 383 return img_zoom(&img, (prefix ? prefix : zl) / 100.0); 384 } 385 386 bool ci_fit_to_win(arg_t sm) 387 { 388 return img_fit_win(&img, sm); 389 } 390 391 bool ci_rotate(arg_t degree) 392 { 393 img_rotate(&img, degree); 394 return true; 395 } 396 397 bool ci_flip(arg_t dir) 398 { 399 img_flip(&img, dir); 400 return true; 401 } 402 403 bool ci_toggle_antialias(arg_t _) 404 { 405 img_toggle_antialias(&img); 406 return true; 407 } 408 409 bool ci_toggle_alpha(arg_t _) 410 { 411 img.alpha = !img.alpha; 412 img.dirty = true; 413 return true; 414 } 415 416 bool ci_slideshow(arg_t _) 417 { 418 if (prefix > 0) { 419 img.ss.on = true; 420 img.ss.delay = prefix * 10; 421 set_timeout(slideshow, img.ss.delay * 100, true); 422 } else if (img.ss.on) { 423 img.ss.on = false; 424 reset_timeout(slideshow); 425 } else { 426 img.ss.on = true; 427 } 428 return true; 429 } 430 431 bool ct_move_sel(arg_t dir) 432 { 433 return tns_move_selection(&tns, dir, prefix); 434 } 435 436 bool ct_reload_all(arg_t _) 437 { 438 tns_free(&tns); 439 tns_init(&tns, files, &filecnt, &fileidx, &win); 440 tns.dirty = true; 441 return true; 442 } 443 444 445 #undef G_CMD 446 #define G_CMD(c) { -1, cg_##c }, 447 #undef I_CMD 448 #define I_CMD(c) { MODE_IMAGE, ci_##c }, 449 #undef T_CMD 450 #define T_CMD(c) { MODE_THUMB, ct_##c }, 451 452 const cmd_t cmds[CMD_COUNT] = { 453 #include "commands.lst" 454 }; 455