/* Hack for use instead of xmag */ /* * Copyright (C) 2002 Red Hat Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301, USA. */ #define _GNU_SOURCE #define _XOPEN_SOURCE 600 /* C99 -- for rint() */ #include #include #include #include #include #include static GtkWidget *grab_widget = NULL; static GtkWidget *display_window = NULL; static int last_grab_x = 0; static int last_grab_y = 0; static int last_grab_width = 150; static int last_grab_height = 150; static GtkAllocation last_grab_allocation; static double width_factor = 4.0; static double height_factor = 4.0; static GdkInterpType interp_mode = GDK_INTERP_NEAREST; static guint regrab_idle_id = 0; static GdkPixbuf* get_pixbuf (void) { GdkPixbuf *screenshot; GdkPixbuf *magnified; #if 0 g_print ("Size %d x %d\n", last_grab_width, last_grab_height); #endif screenshot = gdk_pixbuf_get_from_window(gdk_get_default_root_window(), last_grab_x, last_grab_y, last_grab_width, last_grab_height); if (screenshot == NULL) { g_printerr ("Screenshot failed\n"); exit (1); } magnified = gdk_pixbuf_scale_simple (screenshot, last_grab_width * width_factor, last_grab_height * height_factor, interp_mode); g_object_unref (G_OBJECT (screenshot)); return magnified; } static gboolean regrab_idle (GtkWidget *image) { GdkPixbuf *magnified; GtkAllocation allocation; gtk_widget_get_allocation (image, &allocation); if (allocation.width != last_grab_allocation.width || allocation.height != last_grab_allocation.height) { last_grab_width = rint (allocation.width / width_factor); last_grab_height = rint (allocation.height / height_factor); last_grab_allocation = allocation; magnified = get_pixbuf (); gtk_image_set_from_pixbuf (GTK_IMAGE (image), magnified); g_object_unref (G_OBJECT (magnified)); } regrab_idle_id = 0; return FALSE; } static void image_resized (GtkWidget *image) { if (regrab_idle_id == 0) regrab_idle_id = g_idle_add_full (G_PRIORITY_LOW + 100, (GSourceFunc) regrab_idle, image, NULL); } static void grab_area_at_mouse (GtkWidget *invisible, int x_root, int y_root) { GdkPixbuf *magnified; int width, height; GtkWidget *widget; width = last_grab_width; height = last_grab_height; last_grab_x = x_root; last_grab_y = y_root; last_grab_width = width; last_grab_height = height; magnified = get_pixbuf (); display_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size (GTK_WINDOW (display_window), last_grab_width, last_grab_height); widget = gtk_image_new_from_pixbuf (magnified); gtk_widget_set_size_request (widget, 40, 40); gtk_container_add (GTK_CONTAINER (display_window), widget); g_object_unref (G_OBJECT (magnified)); g_object_add_weak_pointer (G_OBJECT (display_window), (gpointer) &display_window); g_signal_connect (G_OBJECT (display_window), "destroy", G_CALLBACK (gtk_main_quit), NULL); g_signal_connect_after (G_OBJECT (widget), "size_allocate", G_CALLBACK (image_resized), NULL); gtk_widget_show_all (display_window); } static void shutdown_grab (void) { GdkDeviceManager *manager = gdk_display_get_device_manager (gdk_display_get_default ()); GdkDevice *device = gdk_device_manager_get_client_pointer (manager); gdk_device_ungrab (device, gtk_get_current_event_time ()); gdk_device_ungrab (gdk_device_get_associated_device (device), gtk_get_current_event_time ()); gtk_grab_remove (grab_widget); } static void mouse_motion (GtkWidget *invisible, GdkEventMotion *event, gpointer data) { } static gboolean mouse_release (GtkWidget *invisible, GdkEventButton *event, gpointer data) { if (event->button != 1) return FALSE; grab_area_at_mouse (invisible, event->x_root, event->y_root); shutdown_grab (); g_signal_handlers_disconnect_by_func (invisible, mouse_motion, NULL); g_signal_handlers_disconnect_by_func (invisible, mouse_release, NULL); return TRUE; } /* Helper Functions */ static gboolean mouse_press (GtkWidget *invisible, GdkEventButton *event, gpointer data); static gboolean key_press (GtkWidget *invisible, GdkEventKey *event, gpointer data) { if (event->keyval == GDK_KEY_Escape) { shutdown_grab (); g_signal_handlers_disconnect_by_func (invisible, mouse_press, NULL); g_signal_handlers_disconnect_by_func (invisible, key_press, NULL); return TRUE; } return FALSE; } static gboolean mouse_press (GtkWidget *invisible, GdkEventButton *event, gpointer data) { if (event->type == GDK_BUTTON_PRESS && event->button == 1) { g_signal_connect (invisible, "motion_notify_event", G_CALLBACK (mouse_motion), NULL); g_signal_connect (invisible, "button_release_event", G_CALLBACK (mouse_release), NULL); g_signal_handlers_disconnect_by_func (invisible, mouse_press, NULL); g_signal_handlers_disconnect_by_func (invisible, key_press, NULL); return TRUE; } return FALSE; } static void begin_area_grab (void) { GdkWindow *window; GdkDeviceManager *manager; GdkDevice *device; if (grab_widget == NULL) { grab_widget = gtk_invisible_new (); gtk_widget_add_events (grab_widget, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK); gtk_widget_show (grab_widget); } window = gtk_widget_get_window (grab_widget); manager = gdk_display_get_device_manager (gdk_display_get_default ()); device = gdk_device_manager_get_client_pointer (manager); if (gdk_device_grab (device, window, GDK_OWNERSHIP_NONE, FALSE, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK, NULL, gtk_get_current_event_time ()) != GDK_GRAB_SUCCESS) { g_warning ("Failed to grab pointer to do eyedropper"); return; } if (gdk_device_grab (gdk_device_get_associated_device (device), window, GDK_OWNERSHIP_NONE, FALSE, GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK, NULL, gtk_get_current_event_time ()) != GDK_GRAB_SUCCESS) { gdk_device_ungrab (device, gtk_get_current_event_time ()); g_warning ("Failed to grab keyboard to do eyedropper"); return; } gtk_grab_add (grab_widget); g_signal_connect (grab_widget, "button_press_event", G_CALLBACK (mouse_press), NULL); g_signal_connect (grab_widget, "key_press_event", G_CALLBACK (key_press), NULL); } int main (int argc, char **argv) { gtk_init (&argc, &argv); begin_area_grab (); gtk_main (); return 0; }