00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #define _GNU_SOURCE
00023 #define _XOPEN_SOURCE 600
00024
00025 #include <gtk/gtk.h>
00026 #include <gdk/gdkx.h>
00027 #include <gdk/gdkkeysyms.h>
00028 #include <unistd.h>
00029 #include <stdlib.h>
00030 #include <math.h>
00031
00032 static GtkWidget *grab_widget = NULL;
00033 static GtkWidget *display_window = NULL;
00034 static int last_grab_x = 0;
00035 static int last_grab_y = 0;
00036 static int last_grab_width = 150;
00037 static int last_grab_height = 150;
00038 static GtkAllocation last_grab_allocation;
00039 static double width_factor = 4.0;
00040 static double height_factor = 4.0;
00041 static GdkInterpType interp_mode = GDK_INTERP_NEAREST;
00042 static guint regrab_idle_id = 0;
00043
00044 static GdkPixbuf*
00045 get_pixbuf (void)
00046 {
00047 GdkPixbuf *screenshot;
00048 GdkPixbuf *magnified;
00049
00050 #if 0
00051 g_print ("Size %d x %d\n",
00052 last_grab_width, last_grab_height);
00053 #endif
00054
00055 screenshot = gdk_pixbuf_get_from_drawable (NULL, gdk_get_default_root_window (),
00056 NULL,
00057 last_grab_x, last_grab_y, 0, 0,
00058 last_grab_width, last_grab_height);
00059
00060 if (screenshot == NULL)
00061 {
00062 g_printerr ("Screenshot failed\n");
00063 exit (1);
00064 }
00065
00066 magnified = gdk_pixbuf_scale_simple (screenshot, last_grab_width * width_factor,
00067 last_grab_height * height_factor,
00068 interp_mode);
00069
00070
00071 g_object_unref (G_OBJECT (screenshot));
00072
00073 return magnified;
00074 }
00075
00076 static gboolean
00077 regrab_idle (GtkWidget *image)
00078 {
00079 GdkPixbuf *magnified;
00080
00081 if (image->allocation.width != last_grab_allocation.width ||
00082 image->allocation.height != last_grab_allocation.height)
00083 {
00084 last_grab_width = rint (image->allocation.width / width_factor);
00085 last_grab_height = rint (image->allocation.height / height_factor);
00086 last_grab_allocation = image->allocation;
00087
00088 magnified = get_pixbuf ();
00089
00090 gtk_image_set_from_pixbuf (GTK_IMAGE (image), magnified);
00091
00092 g_object_unref (G_OBJECT (magnified));
00093 }
00094
00095 regrab_idle_id = 0;
00096
00097 return FALSE;
00098 }
00099
00100 static void
00101 image_resized (GtkWidget *image)
00102 {
00103 if (regrab_idle_id == 0)
00104 regrab_idle_id = g_idle_add_full (G_PRIORITY_LOW + 100, (GSourceFunc) regrab_idle,
00105 image, NULL);
00106 }
00107
00108 static void
00109 grab_area_at_mouse (GtkWidget *invisible,
00110 int x_root,
00111 int y_root)
00112 {
00113 GdkPixbuf *magnified;
00114 int width, height;
00115 GtkWidget *widget;
00116
00117 width = last_grab_width;
00118 height = last_grab_height;
00119
00120 last_grab_x = x_root;
00121 last_grab_y = y_root;
00122 last_grab_width = width;
00123 last_grab_height = height;
00124
00125 magnified = get_pixbuf ();
00126
00127 display_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
00128 gtk_window_set_default_size (GTK_WINDOW (display_window),
00129 last_grab_width, last_grab_height);
00130 widget = gtk_image_new_from_pixbuf (magnified);
00131 gtk_widget_set_size_request (widget, 40, 40);
00132 gtk_container_add (GTK_CONTAINER (display_window), widget);
00133 g_object_unref (G_OBJECT (magnified));
00134
00135 g_object_add_weak_pointer (G_OBJECT (display_window),
00136 (gpointer) &display_window);
00137
00138 g_signal_connect (G_OBJECT (display_window), "destroy",
00139 G_CALLBACK (gtk_main_quit), NULL);
00140
00141 g_signal_connect_after (G_OBJECT (widget), "size_allocate", G_CALLBACK (image_resized), NULL);
00142
00143 gtk_widget_show_all (display_window);
00144 }
00145
00146 static void
00147 shutdown_grab (void)
00148 {
00149 gdk_keyboard_ungrab (gtk_get_current_event_time ());
00150 gdk_pointer_ungrab (gtk_get_current_event_time ());
00151 gtk_grab_remove (grab_widget);
00152 }
00153
00154 static void
00155 mouse_motion (GtkWidget *invisible,
00156 GdkEventMotion *event,
00157 gpointer data)
00158 {
00159
00160 }
00161
00162 static gboolean
00163 mouse_release (GtkWidget *invisible,
00164 GdkEventButton *event,
00165 gpointer data)
00166 {
00167 if (event->button != 1)
00168 return FALSE;
00169
00170 grab_area_at_mouse (invisible, event->x_root, event->y_root);
00171
00172 shutdown_grab ();
00173
00174 gtk_signal_disconnect_by_func (GTK_OBJECT (invisible),
00175 GTK_SIGNAL_FUNC (mouse_motion), NULL);
00176 gtk_signal_disconnect_by_func (GTK_OBJECT (invisible),
00177 GTK_SIGNAL_FUNC (mouse_release), NULL);
00178
00179 return TRUE;
00180 }
00181
00182
00183
00184 static gboolean mouse_press (GtkWidget *invisible,
00185 GdkEventButton *event,
00186 gpointer data);
00187
00188 static gboolean
00189 key_press (GtkWidget *invisible,
00190 GdkEventKey *event,
00191 gpointer data)
00192 {
00193 if (event->keyval == GDK_Escape)
00194 {
00195 shutdown_grab ();
00196
00197 gtk_signal_disconnect_by_func (GTK_OBJECT (invisible),
00198 GTK_SIGNAL_FUNC (mouse_press),
00199 NULL);
00200 gtk_signal_disconnect_by_func (GTK_OBJECT (invisible),
00201 GTK_SIGNAL_FUNC (key_press),
00202 NULL);
00203
00204 return TRUE;
00205 }
00206
00207 return FALSE;
00208 }
00209
00210 static gboolean
00211 mouse_press (GtkWidget *invisible,
00212 GdkEventButton *event,
00213 gpointer data)
00214 {
00215 if (event->type == GDK_BUTTON_PRESS &&
00216 event->button == 1)
00217 {
00218 g_signal_connect (invisible, "motion_notify_event",
00219 G_CALLBACK (mouse_motion), NULL);
00220 g_signal_connect (invisible, "button_release_event",
00221 G_CALLBACK (mouse_release), NULL);
00222 gtk_signal_disconnect_by_func (GTK_OBJECT (invisible),
00223 GTK_SIGNAL_FUNC (mouse_press),
00224 NULL);
00225 gtk_signal_disconnect_by_func (GTK_OBJECT (invisible),
00226 GTK_SIGNAL_FUNC (key_press),
00227 NULL);
00228 return TRUE;
00229 }
00230
00231 return FALSE;
00232 }
00233
00234 static void
00235 begin_area_grab (void)
00236 {
00237 if (grab_widget == NULL)
00238 {
00239 grab_widget = gtk_invisible_new ();
00240
00241 gtk_widget_add_events (grab_widget,
00242 GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK);
00243
00244 gtk_widget_show (grab_widget);
00245 }
00246
00247 if (gdk_keyboard_grab (grab_widget->window,
00248 FALSE,
00249 gtk_get_current_event_time ()) != GDK_GRAB_SUCCESS)
00250 {
00251 g_warning ("Failed to grab keyboard to do eyedropper");
00252 return;
00253 }
00254
00255 if (gdk_pointer_grab (grab_widget->window,
00256 FALSE,
00257 GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK,
00258 NULL,
00259 NULL,
00260 gtk_get_current_event_time ()) != GDK_GRAB_SUCCESS)
00261 {
00262 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
00263 g_warning ("Failed to grab pointer to do eyedropper");
00264 return;
00265 }
00266
00267 gtk_grab_add (grab_widget);
00268
00269 g_signal_connect (grab_widget, "button_press_event",
00270 G_CALLBACK (mouse_press), NULL);
00271 g_signal_connect (grab_widget, "key_press_event",
00272 G_CALLBACK (key_press), NULL);
00273 }
00274
00275 int
00276 main (int argc, char **argv)
00277 {
00278 gtk_init (&argc, &argv);
00279
00280 begin_area_grab ();
00281
00282 gtk_main ();
00283
00284 return 0;
00285 }