Commit 0ebad762 authored by Cosimo Cecchi's avatar Cosimo Cecchi

screenshot: move the interactive area selection into a separate file

parent 1f29a037
......@@ -15,6 +15,8 @@ gnome_screenshot_SOURCES = \
gnome-screenshot.c \
cheese-flash.c \
cheese-flash.h \
screenshot-area-selection.c \
screenshot-area-selection.h \
screenshot-config.c \
screenshot-config.h \
screenshot-dialog.c \
......
......@@ -41,6 +41,7 @@
#include <X11/Xutil.h>
#include <canberra-gtk.h>
#include "screenshot-area-selection.h"
#include "screenshot-config.h"
#include "screenshot-filename-builder.h"
#include "screenshot-interactive-dialog.h"
......
/* screenshot-area-selection.c - interactive screenshot area selection
*
* Copyright (C) 2001-2006 Jonathan Blandford <jrb@alum.mit.edu>
* Copyright (C) 2008 Cosimo Cecchi <cosimoc@gnome.org>
*
* 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., 59 Temple Place - Suite 330,
*/
#include <config.h>
#include <gtk/gtk.h>
#include "screenshot-area-selection.h"
typedef struct {
GdkRectangle rect;
gboolean button_pressed;
GtkWidget *window;
} select_area_filter_data;
static gboolean
select_area_button_press (GtkWidget *window,
GdkEventButton *event,
select_area_filter_data *data)
{
if (data->button_pressed)
return TRUE;
data->button_pressed = TRUE;
data->rect.x = event->x_root;
data->rect.y = event->y_root;
return TRUE;
}
static gboolean
select_area_motion_notify (GtkWidget *window,
GdkEventMotion *event,
select_area_filter_data *data)
{
GdkRectangle draw_rect;
if (!data->button_pressed)
return TRUE;
draw_rect.width = ABS (data->rect.x - event->x_root);
draw_rect.height = ABS (data->rect.y - event->y_root);
draw_rect.x = MIN (data->rect.x, event->x_root);
draw_rect.y = MIN (data->rect.y, event->y_root);
if (draw_rect.width <= 0 || draw_rect.height <= 0)
{
gtk_window_move (GTK_WINDOW (window), -100, -100);
gtk_window_resize (GTK_WINDOW (window), 10, 10);
return TRUE;
}
gtk_window_move (GTK_WINDOW (window), draw_rect.x, draw_rect.y);
gtk_window_resize (GTK_WINDOW (window), draw_rect.width, draw_rect.height);
/* We (ab)use app-paintable to indicate if we have an RGBA window */
if (!gtk_widget_get_app_paintable (window))
{
GdkWindow *gdkwindow = gtk_widget_get_window (window);
/* Shape the window to make only the outline visible */
if (draw_rect.width > 2 && draw_rect.height > 2)
{
cairo_region_t *region;
cairo_rectangle_int_t region_rect = {
0, 0,
draw_rect.width, draw_rect.height
};
region = cairo_region_create_rectangle (&region_rect);
region_rect.x++;
region_rect.y++;
region_rect.width -= 2;
region_rect.height -= 2;
cairo_region_subtract_rectangle (region, &region_rect);
gdk_window_shape_combine_region (gdkwindow, region, 0, 0);
cairo_region_destroy (region);
}
else
gdk_window_shape_combine_region (gdkwindow, NULL, 0, 0);
}
return TRUE;
}
static gboolean
select_area_button_release (GtkWidget *window,
GdkEventButton *event,
select_area_filter_data *data)
{
if (!data->button_pressed)
return TRUE;
data->rect.width = ABS (data->rect.x - event->x_root);
data->rect.height = ABS (data->rect.y - event->y_root);
data->rect.x = MIN (data->rect.x, event->x_root);
data->rect.y = MIN (data->rect.y, event->y_root);
gtk_main_quit ();
return TRUE;
}
static gboolean
select_area_key_press (GtkWidget *window,
GdkEventKey *event,
select_area_filter_data *data)
{
if (event->keyval == GDK_KEY_Escape)
{
data->rect.x = 0;
data->rect.y = 0;
data->rect.width = 0;
data->rect.height = 0;
gtk_main_quit ();
}
return TRUE;
}
static gboolean
select_window_draw (GtkWidget *window, cairo_t *cr, gpointer unused)
{
GtkAllocation allocation;
GtkStyle *style;
style = gtk_widget_get_style (window);
if (gtk_widget_get_app_paintable (window))
{
cairo_set_line_width (cr, 1.0);
gtk_widget_get_allocation (window, &allocation);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba (cr, 0, 0, 0, 0);
cairo_paint (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
gdk_cairo_set_source_color (cr, &style->base[GTK_STATE_SELECTED]);
cairo_paint_with_alpha (cr, 0.25);
cairo_rectangle (cr,
allocation.x + 0.5, allocation.y + 0.5,
allocation.width - 1, allocation.height - 1);
cairo_stroke (cr);
}
else
{
gdk_cairo_set_source_color (cr, &style->base[GTK_STATE_SELECTED]);
cairo_paint (cr);
}
return TRUE;
}
static GtkWidget *
create_select_window (void)
{
GtkWidget *window;
GdkScreen *screen;
GdkVisual *visual;
screen = gdk_screen_get_default ();
visual = gdk_screen_get_rgba_visual (screen);
window = gtk_window_new (GTK_WINDOW_POPUP);
if (gdk_screen_is_composited (screen) && visual)
{
gtk_widget_set_visual (window, visual);
gtk_widget_set_app_paintable (window, TRUE);
}
g_signal_connect (window, "draw", G_CALLBACK (select_window_draw), NULL);
gtk_window_move (GTK_WINDOW (window), -100, -100);
gtk_window_resize (GTK_WINDOW (window), 10, 10);
gtk_widget_show (window);
return window;
}
typedef struct {
GdkRectangle rectangle;
SelectAreaCallback callback;
} CallbackData;
static gboolean
emit_select_callback_in_idle (gpointer user_data)
{
CallbackData *data = user_data;
data->callback (&data->rectangle);
g_slice_free (CallbackData, data);
return FALSE;
}
void
screenshot_select_area_async (SelectAreaCallback callback)
{
GdkCursor *cursor;
select_area_filter_data data;
CallbackData *cb_data;
data.rect.x = 0;
data.rect.y = 0;
data.rect.width = 0;
data.rect.height = 0;
data.button_pressed = FALSE;
data.window = create_select_window();
cb_data = g_slice_new0 (CallbackData);
cb_data->callback = callback;
g_signal_connect (data.window, "key-press-event", G_CALLBACK (select_area_key_press), &data);
g_signal_connect (data.window, "button-press-event", G_CALLBACK (select_area_button_press), &data);
g_signal_connect (data.window, "button-release-event", G_CALLBACK (select_area_button_release), &data);
g_signal_connect (data.window, "motion-notify-event", G_CALLBACK (select_area_motion_notify), &data);
cursor = gdk_cursor_new (GDK_CROSSHAIR);
if (gdk_pointer_grab (gtk_widget_get_window (data.window), FALSE,
GDK_POINTER_MOTION_MASK|GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK,
NULL, cursor,
GDK_CURRENT_TIME) != GDK_GRAB_SUCCESS)
{
gdk_cursor_unref (cursor);
goto out;
}
if (gdk_keyboard_grab (gtk_widget_get_window (data.window), FALSE, GDK_CURRENT_TIME) != GDK_GRAB_SUCCESS)
{
gdk_pointer_ungrab (GDK_CURRENT_TIME);
gdk_cursor_unref (cursor);
goto out;
}
gtk_main ();
gdk_keyboard_ungrab (GDK_CURRENT_TIME);
gdk_pointer_ungrab (GDK_CURRENT_TIME);
gtk_widget_destroy (data.window);
gdk_cursor_unref (cursor);
gdk_flush ();
out:
cb_data->rectangle = data.rect;
/* FIXME: we should actually be emitting the callback When
* the compositor has finished re-drawing, but there seems to be no easy
* way to know that.
*/
g_timeout_add (200, emit_select_callback_in_idle, cb_data);
}
/* screenshot-area-selection.h - interactive screenshot area selection
*
* Copyright (C) 2001-2006 Jonathan Blandford <jrb@alum.mit.edu>
* Copyright (C) 2008 Cosimo Cecchi <cosimoc@gnome.org>
*
* 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., 59 Temple Place - Suite 330,
*/
#ifndef __SCREENSHOT_AREA_SELECTION_H__
#define __SCREENSHOT_AREA_SELECTION_H__
#include <gdk/gdk.h>
G_BEGIN_DECLS
typedef void (* SelectAreaCallback) (GdkRectangle *rectangle);
void screenshot_select_area_async (SelectAreaCallback callback);
G_END_DECLS
#endif /* __SCREENSHOT_AREA_SELECTION_H__ */
......@@ -141,258 +141,6 @@ screenshot_find_current_window ()
return current_window;
}
typedef struct {
GdkRectangle rect;
gboolean button_pressed;
GtkWidget *window;
} select_area_filter_data;
static gboolean
select_area_button_press (GtkWidget *window,
GdkEventButton *event,
select_area_filter_data *data)
{
if (data->button_pressed)
return TRUE;
data->button_pressed = TRUE;
data->rect.x = event->x_root;
data->rect.y = event->y_root;
return TRUE;
}
static gboolean
select_area_motion_notify (GtkWidget *window,
GdkEventMotion *event,
select_area_filter_data *data)
{
GdkRectangle draw_rect;
if (!data->button_pressed)
return TRUE;
draw_rect.width = ABS (data->rect.x - event->x_root);
draw_rect.height = ABS (data->rect.y - event->y_root);
draw_rect.x = MIN (data->rect.x, event->x_root);
draw_rect.y = MIN (data->rect.y, event->y_root);
if (draw_rect.width <= 0 || draw_rect.height <= 0)
{
gtk_window_move (GTK_WINDOW (window), -100, -100);
gtk_window_resize (GTK_WINDOW (window), 10, 10);
return TRUE;
}
gtk_window_move (GTK_WINDOW (window), draw_rect.x, draw_rect.y);
gtk_window_resize (GTK_WINDOW (window), draw_rect.width, draw_rect.height);
/* We (ab)use app-paintable to indicate if we have an RGBA window */
if (!gtk_widget_get_app_paintable (window))
{
GdkWindow *gdkwindow = gtk_widget_get_window (window);
/* Shape the window to make only the outline visible */
if (draw_rect.width > 2 && draw_rect.height > 2)
{
cairo_region_t *region;
cairo_rectangle_int_t region_rect = {
0, 0,
draw_rect.width, draw_rect.height
};
region = cairo_region_create_rectangle (&region_rect);
region_rect.x++;
region_rect.y++;
region_rect.width -= 2;
region_rect.height -= 2;
cairo_region_subtract_rectangle (region, &region_rect);
gdk_window_shape_combine_region (gdkwindow, region, 0, 0);
cairo_region_destroy (region);
}
else
gdk_window_shape_combine_region (gdkwindow, NULL, 0, 0);
}
return TRUE;
}
static gboolean
select_area_button_release (GtkWidget *window,
GdkEventButton *event,
select_area_filter_data *data)
{
if (!data->button_pressed)
return TRUE;
data->rect.width = ABS (data->rect.x - event->x_root);
data->rect.height = ABS (data->rect.y - event->y_root);
data->rect.x = MIN (data->rect.x, event->x_root);
data->rect.y = MIN (data->rect.y, event->y_root);
gtk_main_quit ();
return TRUE;
}
static gboolean
select_area_key_press (GtkWidget *window,
GdkEventKey *event,
select_area_filter_data *data)
{
if (event->keyval == GDK_KEY_Escape)
{
data->rect.x = 0;
data->rect.y = 0;
data->rect.width = 0;
data->rect.height = 0;
gtk_main_quit ();
}
return TRUE;
}
static gboolean
select_window_draw (GtkWidget *window, cairo_t *cr, gpointer unused)
{
GtkAllocation allocation;
GtkStyle *style;
style = gtk_widget_get_style (window);
if (gtk_widget_get_app_paintable (window))
{
cairo_set_line_width (cr, 1.0);
gtk_widget_get_allocation (window, &allocation);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba (cr, 0, 0, 0, 0);
cairo_paint (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
gdk_cairo_set_source_color (cr, &style->base[GTK_STATE_SELECTED]);
cairo_paint_with_alpha (cr, 0.25);
cairo_rectangle (cr,
allocation.x + 0.5, allocation.y + 0.5,
allocation.width - 1, allocation.height - 1);
cairo_stroke (cr);
}
else
{
gdk_cairo_set_source_color (cr, &style->base[GTK_STATE_SELECTED]);
cairo_paint (cr);
}
return TRUE;
}
static GtkWidget *
create_select_window (void)
{
GtkWidget *window;
GdkScreen *screen;
GdkVisual *visual;
screen = gdk_screen_get_default ();
visual = gdk_screen_get_rgba_visual (screen);
window = gtk_window_new (GTK_WINDOW_POPUP);
if (gdk_screen_is_composited (screen) && visual)
{
gtk_widget_set_visual (window, visual);
gtk_widget_set_app_paintable (window, TRUE);
}
g_signal_connect (window, "draw", G_CALLBACK (select_window_draw), NULL);
gtk_window_move (GTK_WINDOW (window), -100, -100);
gtk_window_resize (GTK_WINDOW (window), 10, 10);
gtk_widget_show (window);
return window;
}
typedef struct {
GdkRectangle rectangle;
SelectAreaCallback callback;
} CallbackData;
static gboolean
emit_select_callback_in_idle (gpointer user_data)
{
CallbackData *data = user_data;
data->callback (&data->rectangle);
g_slice_free (CallbackData, data);
return FALSE;
}
void
screenshot_select_area_async (SelectAreaCallback callback)
{
GdkCursor *cursor;
select_area_filter_data data;
CallbackData *cb_data;
data.rect.x = 0;
data.rect.y = 0;
data.rect.width = 0;
data.rect.height = 0;
data.button_pressed = FALSE;
data.window = create_select_window();
cb_data = g_slice_new0 (CallbackData);
cb_data->callback = callback;
g_signal_connect (data.window, "key-press-event", G_CALLBACK (select_area_key_press), &data);
g_signal_connect (data.window, "button-press-event", G_CALLBACK (select_area_button_press), &data);
g_signal_connect (data.window, "button-release-event", G_CALLBACK (select_area_button_release), &data);
g_signal_connect (data.window, "motion-notify-event", G_CALLBACK (select_area_motion_notify), &data);
cursor = gdk_cursor_new (GDK_CROSSHAIR);
if (gdk_pointer_grab (gtk_widget_get_window (data.window), FALSE,
GDK_POINTER_MOTION_MASK|GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK,
NULL, cursor,
GDK_CURRENT_TIME) != GDK_GRAB_SUCCESS)
{
gdk_cursor_unref (cursor);
goto out;
}
if (gdk_keyboard_grab (gtk_widget_get_window (data.window), FALSE, GDK_CURRENT_TIME) != GDK_GRAB_SUCCESS)
{
gdk_pointer_ungrab (GDK_CURRENT_TIME);
gdk_cursor_unref (cursor);
goto out;
}
gtk_main ();
gdk_keyboard_ungrab (GDK_CURRENT_TIME);
gdk_pointer_ungrab (GDK_CURRENT_TIME);
gtk_widget_destroy (data.window);
gdk_cursor_unref (cursor);
gdk_flush ();
out:
cb_data->rectangle = data.rect;
/* FIXME: we should actually be emitting the callback When
* the compositor has finished re-drawing, but there seems to be no easy
* way to know that.
*/
g_timeout_add (200, emit_select_callback_in_idle, cb_data);
}
static Window
find_wm_window (GdkWindow *window)
{
......
......@@ -25,14 +25,11 @@
G_BEGIN_DECLS
typedef void (* SelectAreaCallback) (GdkRectangle *rectangle);
gboolean screenshot_grab_lock (void);
void screenshot_release_lock (void);
void screenshot_get_window_rect (GdkWindow *win,
GdkRectangle *rect);
GdkWindow *screenshot_find_current_window (void);
void screenshot_select_area_async (SelectAreaCallback callback);
GdkPixbuf *screenshot_get_pixbuf (GdkWindow *win,
GdkRectangle *rectangle);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment