static void discover (void) { xcb_query_tree_reply_t *r; xcb_window_t *c; r = xcb_query_tree_reply(conn, xcb_query_tree(conn, scr->root), NULL); if (r == NULL) { warnx("cannot get a list of windows"); return; } c = xcb_query_tree_children(r); for (unsigned int i = 0; i < r->children_len; i++) { setup_win(c[i]); focus(c[i], INACTIVE); } nextwin(); }
static void events_loop (void) { uint32_t values[3]; xcb_generic_event_t *ev; xcb_get_geometry_reply_t *geom; xcb_window_t win = 0; /* loop */ for (;;) { ev = xcb_wait_for_event(conn); if (ev == NULL) errx(1, "xcb connection broken"); switch (ev->response_type & ~0x80) { case XCB_CREATE_NOTIFY: { xcb_create_notify_event_t *e; e = (xcb_create_notify_event_t *)ev; if (!e->override_redirect) { setup_win(e->window); focus(e->window, ACTIVE); } } break; case XCB_DESTROY_NOTIFY: { xcb_destroy_notify_event_t *e; e = (xcb_destroy_notify_event_t *)ev; xcb_kill_client(conn, e->window); } break; case XCB_KEY_PRESS: { xcb_key_press_event_t *e; e = (xcb_key_press_event_t *)ev; xcb_keysym_t keysym = xcb_get_keysym(e->detail); for (unsigned int i=0; i < LENGTH(keys); i++) { if (keys[i].keysym == keysym && CLEANMASK(keys[i].mod) == CLEANMASK(e->state) && keys[i].mfunc) { keys[i].mfunc(keys[i].x, keys[i].y); } else if (keys[i].keysym == keysym && CLEANMASK(keys[i].mod) == CLEANMASK(e->state) && keys[i].func) { keys[i].func(); } } } break; case XCB_ENTER_NOTIFY: { xcb_enter_notify_event_t *e; e = (xcb_enter_notify_event_t *)ev; focus(e->event, ACTIVE); } break; case XCB_MAP_NOTIFY: { xcb_map_notify_event_t *e; e = (xcb_map_notify_event_t *)ev; if (!e->override_redirect) { xcb_map_window(conn, e->window); xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, e->window, XCB_CURRENT_TIME); } } break; case XCB_BUTTON_PRESS: { xcb_button_press_event_t *e; e = ( xcb_button_press_event_t *)ev; win = e->child; if (!win || win == scr->root) break; values[0] = XCB_STACK_MODE_ABOVE; xcb_configure_window(conn, win, XCB_CONFIG_WINDOW_STACK_MODE, values); geom = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, win), NULL); if (1 == e->detail) { values[2] = 1; center_pointer(win); } else { values[2] = 3; xcb_warp_pointer(conn, XCB_NONE, win, 0, 0, 0, 0, geom->width, geom->height); } xcb_grab_pointer(conn, 0, scr->root, XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION | XCB_EVENT_MASK_POINTER_MOTION_HINT, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, scr->root, XCB_NONE, XCB_CURRENT_TIME); xcb_flush(conn); } break; case XCB_MOTION_NOTIFY: { xcb_query_pointer_reply_t *pointer; pointer = xcb_query_pointer_reply(conn, xcb_query_pointer(conn, scr->root), 0); if (values[2] == 1) { geom = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, win), NULL); if (!geom) { break; } values[0] = (pointer->root_x + geom->width / 2 > scr->width_in_pixels - (BORDERWIDTH*2)) ? scr->width_in_pixels - geom->width - (BORDERWIDTH*2) : pointer->root_x - geom->width / 2; values[1] = (pointer->root_y + geom->height / 2 > scr->height_in_pixels - (BORDERWIDTH*2)) ? (scr->height_in_pixels - geom->height - (BORDERWIDTH*2)) : pointer->root_y - geom->height / 2; if (pointer->root_x < geom->width/2) values[0] = 0; if (pointer->root_y < geom->height/2) values[1] = 0; xcb_configure_window(conn, win, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values); xcb_flush(conn); } else if (values[2] == 3) { focus(win, RESIZE); geom = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, win), NULL); values[0] = pointer->root_x - geom->x; values[1] = pointer->root_y - geom->y; xcb_configure_window(conn, win, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values); xcb_flush(conn); } } break; case XCB_BUTTON_RELEASE: focus(win, ACTIVE); xcb_ungrab_pointer(conn, XCB_CURRENT_TIME); break; } xcb_flush(conn); free(ev); } }
/* * Load & display image */ void qiv_load_image(qiv_image *q) { /* Don't initialize most variables here, initialize them after load_next_image: */ struct stat st; const char *image_name; Imlib_Image *im; struct timeval load_before, load_after; char is_stat_ok; /* Used to omit slow disk operations if image_file doesn't exist or isn't * a file. */ char is_maybe_image_file; char is_first_error = 1; load_next_image: is_stat_ok = 0; is_maybe_image_file = 1; image_name = image_names[image_idx]; gettimeofday(&load_before, 0); if (imlib_context_get_image()) imlib_free_image(); q->real_w = q->real_h = -2; q->has_thumbnail = FALSE; if (!do_omit_load_stat) { is_stat_ok = 0 == stat(image_name, &st); is_maybe_image_file = is_stat_ok && S_ISREG(st.st_mode); } current_mtime = is_stat_ok ? st.st_mtime : 0; im = NULL; if (thumbnail && fullscreen && (is_stat_ok || maxpect)) { char *th_image_name = is_maybe_image_file ? get_thumbnail_filename(image_name, &is_maybe_image_file) : NULL; if (th_image_name) { im = imlib_load_image(th_image_name); if (im && maxpect) { get_image_dimensions(image_name, th_image_name, &q->real_w, &q->real_h); } free(th_image_name); th_image_name = NULL; } } if (im) { /* We have a dumb thumbnail in im. */ if (maxpect) { current_mtime = 0; q->has_thumbnail = TRUE; /* Now im still has the thumbnail image. Keep it. */ } else { /* Use the real, non-thumbnail image instead. */ imlib_context_set_image(im); imlib_free_image(); im = is_maybe_image_file ? imlib_load_image((char*)image_name) : NULL; } } else { im = is_maybe_image_file ? imlib_load_image((char*)image_name) : NULL; } if (!im) { /* error */ q->error = 1; q->orig_w = 400; q->orig_h = 300; if (to_root || to_root_t || to_root_s) { fprintf(stderr, "qiv: cannot load background_image\n"); qiv_exit(1); } /* Shortcut to speed up lots of subsequent load failures. */ if (is_first_error) { check_size(q, TRUE); if (first) { setup_win(q); first = 0; } gdk_window_set_background(q->win, &error_bg); gdk_beep(); is_first_error = 0; } /* TODO(pts): Avoid the slow loop of copying pointers around in update_image_on_error. */ update_image_on_error(q); /* This is a shortcut to avoid stack overflow in the recursion of * qiv_load_image -> update_image -> qiv_load_image -> update_image -> ... * if there are errors loading many subsequent images. */ goto load_next_image; } if (thumbnail && !q->has_thumbnail && q->real_w < 0 && is_maybe_image_file) { FILE *f = fopen(image_name, "rb"); if (f) { get_real_dimensions_fast(f, &q->real_w, &q->real_h); fclose(f); } } /* Retrieve image properties */ imlib_context_set_image(im); q->error = 0; q->orig_w = imlib_image_get_width(); q->orig_h = imlib_image_get_height(); if (q->orig_w >= (1 << 23) / q->orig_h) { /* Workaround for Imlib2 1.4.6 on Ubuntu Trusty: PNG images with an * alpha channel and pixel count >= (1 << 23) are displayed as black. * imlib_image_query_pixel returns the correct value, but * imlib_render_pixmaps_for_whole_image_at_size renders only black * pixels if unzoomed. */ Imlib_Color c; /* Without this call, imlib_image_set_has_alpha(0) is too early, and * it has no effect. */ imlib_image_query_pixel(0, 0, &c); imlib_image_set_has_alpha(0); } #ifdef HAVE_EXIF if (autorotate) { transform( q, orient( image_name)); } #endif check_size(q, TRUE); if (first) { setup_win(q); first = 0; } /* desktop-background -> exit */ if (to_root || to_root_t || to_root_s) { set_desktop_image(q); if(slide) return; else qiv_exit(0); } gdk_window_set_background(q->win, &image_bg); if (do_grab || (fullscreen && !disable_grab) ) { gdk_keyboard_grab(q->win, FALSE, CurrentTime); gdk_pointer_grab(q->win, FALSE, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK, NULL, NULL, CurrentTime); } gettimeofday(&load_after, 0); /* load_elapsed used by update_image. */ load_elapsed = ((load_after.tv_sec + load_after.tv_usec / 1.0e6) - (load_before.tv_sec + load_before.tv_usec / 1.0e6)); update_image(q, FULL_REDRAW); // if (magnify && !fullscreen) { // [lc] // setup_magnify(q, &magnify_img); // update_magnify(q, &magnify_img, FULL_REDRAW, 0, 0); // } }