mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-10 10:50:10 +00:00
05df57654f
The tablet device is the source device of the event. We must use the source device to properly detect what kind of source we must use to properly set the color.
393 lines
10 KiB
C
393 lines
10 KiB
C
/* GTK - The GIMP Toolkit
|
|
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*
|
|
* Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
|
|
* file for a list of people on the GTK+ Team. See the ChangeLog
|
|
* files for a list of changes. These files are distributed with
|
|
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include <stdio.h>
|
|
#include "gtk/gtk.h"
|
|
#include <math.h>
|
|
|
|
/* Backing surface for drawing area */
|
|
|
|
static cairo_surface_t *surface = NULL;
|
|
|
|
/* Information about cursor */
|
|
|
|
static gint cursor_proximity = TRUE;
|
|
static gdouble cursor_x;
|
|
static gdouble cursor_y;
|
|
|
|
/* Unique ID of current device */
|
|
static GdkDevice *current_device;
|
|
|
|
/* Erase the old cursor, and/or draw a new one, if necessary */
|
|
static void
|
|
update_cursor (GtkWidget *widget, gdouble x, gdouble y)
|
|
{
|
|
static gint cursor_present = 0;
|
|
gint state = !gdk_device_get_has_cursor (current_device) && cursor_proximity;
|
|
|
|
x = floor (x);
|
|
y = floor (y);
|
|
|
|
if (surface != NULL)
|
|
{
|
|
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
|
cairo_t *cr = gdk_cairo_create (gtk_widget_get_window (widget));
|
|
G_GNUC_END_IGNORE_DEPRECATIONS
|
|
|
|
if (cursor_present && (cursor_present != state ||
|
|
x != cursor_x || y != cursor_y))
|
|
{
|
|
cairo_set_source_surface (cr, surface, 0, 0);
|
|
cairo_rectangle (cr, cursor_x - 5, cursor_y - 5, 10, 10);
|
|
cairo_fill (cr);
|
|
}
|
|
|
|
cursor_present = state;
|
|
cursor_x = x;
|
|
cursor_y = y;
|
|
|
|
if (cursor_present)
|
|
{
|
|
cairo_set_source_rgb (cr, 0, 0, 0);
|
|
cairo_rectangle (cr,
|
|
cursor_x - 5, cursor_y -5,
|
|
10, 10);
|
|
cairo_fill (cr);
|
|
}
|
|
|
|
cairo_destroy (cr);
|
|
}
|
|
}
|
|
|
|
/* Create a new backing surface of the appropriate size */
|
|
static gint
|
|
configure_event (GtkWidget *widget, GdkEventConfigure *event)
|
|
{
|
|
GtkAllocation allocation;
|
|
cairo_t *cr;
|
|
|
|
if (surface)
|
|
cairo_surface_destroy (surface);
|
|
|
|
gtk_widget_get_allocation (widget, &allocation);
|
|
|
|
surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget),
|
|
CAIRO_CONTENT_COLOR,
|
|
allocation.width,
|
|
allocation.height);
|
|
cr = cairo_create (surface);
|
|
|
|
cairo_set_source_rgb (cr, 1, 1, 1);
|
|
cairo_paint (cr);
|
|
|
|
cairo_destroy (cr);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* Refill the screen from the backing surface */
|
|
static gboolean
|
|
draw (GtkWidget *widget, cairo_t *cr)
|
|
{
|
|
cairo_set_source_surface (cr, surface, 0, 0);
|
|
cairo_paint (cr);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* Draw a rectangle on the screen, size depending on pressure,
|
|
and color on the type of device */
|
|
static void
|
|
draw_brush (GtkWidget *widget, GdkInputSource source,
|
|
gdouble x, gdouble y, gdouble pressure)
|
|
{
|
|
GdkRGBA color;
|
|
GdkRectangle update_rect;
|
|
cairo_t *cr;
|
|
|
|
color.alpha = 1.0;
|
|
|
|
switch (source)
|
|
{
|
|
case GDK_SOURCE_MOUSE:
|
|
color.red = color.green = 0.0;
|
|
color.blue = 1.0;
|
|
break;
|
|
case GDK_SOURCE_PEN:
|
|
color.red = color.green = color.blue = 0.0;
|
|
break;
|
|
case GDK_SOURCE_ERASER:
|
|
color.red = color.green = color.blue = 1.0;
|
|
break;
|
|
default:
|
|
color.red = color.blue = 0.0;
|
|
color.green = 1.0;
|
|
}
|
|
|
|
update_rect.x = x - 10 * pressure;
|
|
update_rect.y = y - 10 * pressure;
|
|
update_rect.width = 20 * pressure;
|
|
update_rect.height = 20 * pressure;
|
|
|
|
cr = cairo_create (surface);
|
|
gdk_cairo_set_source_rgba (cr, &color);
|
|
gdk_cairo_rectangle (cr, &update_rect);
|
|
cairo_fill (cr);
|
|
cairo_destroy (cr);
|
|
|
|
gtk_widget_queue_draw_area (widget,
|
|
update_rect.x, update_rect.y,
|
|
update_rect.width, update_rect.height);
|
|
gdk_window_process_updates (gtk_widget_get_window (widget), TRUE);
|
|
}
|
|
|
|
static guint32 motion_time;
|
|
|
|
static void
|
|
print_axes (GdkDevice *device, gdouble *axes)
|
|
{
|
|
int i;
|
|
|
|
if (axes)
|
|
{
|
|
g_print ("%s ", gdk_device_get_name (device));
|
|
|
|
for (i = 0; i < gdk_device_get_n_axes (device); i++)
|
|
g_print ("%g ", axes[i]);
|
|
|
|
g_print ("\n");
|
|
}
|
|
}
|
|
|
|
static gint
|
|
button_press_event (GtkWidget *widget, GdkEventButton *event)
|
|
{
|
|
current_device = event->device;
|
|
cursor_proximity = TRUE;
|
|
|
|
if (event->button == GDK_BUTTON_PRIMARY &&
|
|
surface != NULL)
|
|
{
|
|
gdouble pressure = 0.5;
|
|
|
|
print_axes (event->device, event->axes);
|
|
gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_PRESSURE, &pressure);
|
|
draw_brush (widget, gdk_device_get_source (gdk_event_get_source_device (event)),
|
|
event->x, event->y, pressure);
|
|
|
|
motion_time = event->time;
|
|
}
|
|
|
|
update_cursor (widget, event->x, event->y);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gint
|
|
key_press_event (GtkWidget *widget, GdkEventKey *event)
|
|
{
|
|
if ((event->keyval >= 0x20) && (event->keyval <= 0xFF))
|
|
printf("I got a %c\n", event->keyval);
|
|
else
|
|
printf("I got some other key\n");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gint
|
|
motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
|
|
{
|
|
GdkTimeCoord **events;
|
|
gint n_events;
|
|
int i;
|
|
|
|
current_device = event->device;
|
|
cursor_proximity = TRUE;
|
|
|
|
if (event->state & GDK_BUTTON1_MASK && surface != NULL)
|
|
{
|
|
if (gdk_device_get_history (event->device, event->window,
|
|
motion_time, event->time,
|
|
&events, &n_events))
|
|
{
|
|
for (i=0; i<n_events; i++)
|
|
{
|
|
double x = 0, y = 0, pressure = 0.5;
|
|
|
|
gdk_device_get_axis (event->device, events[i]->axes, GDK_AXIS_X, &x);
|
|
gdk_device_get_axis (event->device, events[i]->axes, GDK_AXIS_Y, &y);
|
|
gdk_device_get_axis (event->device, events[i]->axes, GDK_AXIS_PRESSURE, &pressure);
|
|
draw_brush (widget, gdk_device_get_source (gdk_event_get_source_device (event)),
|
|
x, y, pressure);
|
|
|
|
print_axes (gdk_event_get_source_device (event), events[i]->axes);
|
|
}
|
|
gdk_device_free_history (events, n_events);
|
|
}
|
|
else
|
|
{
|
|
double pressure = 0.5;
|
|
|
|
gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_PRESSURE, &pressure);
|
|
|
|
draw_brush (widget, gdk_device_get_source (gdk_event_get_source_device (event)),
|
|
event->x, event->y, pressure);
|
|
}
|
|
motion_time = event->time;
|
|
}
|
|
|
|
|
|
print_axes (event->device, event->axes);
|
|
update_cursor (widget, event->x, event->y);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* We track the next two events to know when we need to draw a
|
|
cursor */
|
|
|
|
static gint
|
|
proximity_out_event (GtkWidget *widget, GdkEventProximity *event)
|
|
{
|
|
cursor_proximity = FALSE;
|
|
update_cursor (widget, cursor_x, cursor_y);
|
|
return TRUE;
|
|
}
|
|
|
|
static gint
|
|
leave_notify_event (GtkWidget *widget, GdkEventCrossing *event)
|
|
{
|
|
cursor_proximity = FALSE;
|
|
update_cursor (widget, cursor_x, cursor_y);
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
quit (void)
|
|
{
|
|
gtk_main_quit ();
|
|
}
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
GList *devices, *d;
|
|
GdkEventMask event_mask;
|
|
GtkWidget *window;
|
|
GtkWidget *drawing_area;
|
|
GtkWidget *vbox;
|
|
GtkWidget *button;
|
|
GdkWindow *gdk_win;
|
|
GdkSeat *seat;
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
seat = gdk_display_get_default_seat (gdk_display_get_default ());
|
|
current_device = gdk_seat_get_pointer (seat);
|
|
|
|
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
gtk_widget_set_name (window, "Test Input");
|
|
|
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
|
gtk_container_add (GTK_CONTAINER (window), vbox);
|
|
gtk_widget_show (vbox);
|
|
|
|
g_signal_connect (window, "destroy",
|
|
G_CALLBACK (quit), NULL);
|
|
|
|
/* Create the drawing area */
|
|
|
|
drawing_area = gtk_drawing_area_new ();
|
|
gtk_widget_set_size_request (drawing_area, 200, 200);
|
|
gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
|
|
|
|
gtk_widget_show (drawing_area);
|
|
|
|
/* Signals used to handle backing surface */
|
|
|
|
g_signal_connect (drawing_area, "draw",
|
|
G_CALLBACK (draw), NULL);
|
|
g_signal_connect (drawing_area, "configure_event",
|
|
G_CALLBACK (configure_event), NULL);
|
|
|
|
/* Event signals */
|
|
|
|
g_signal_connect (drawing_area, "motion_notify_event",
|
|
G_CALLBACK (motion_notify_event), NULL);
|
|
g_signal_connect (drawing_area, "button_press_event",
|
|
G_CALLBACK (button_press_event), NULL);
|
|
g_signal_connect (drawing_area, "key_press_event",
|
|
G_CALLBACK (key_press_event), NULL);
|
|
|
|
g_signal_connect (drawing_area, "leave_notify_event",
|
|
G_CALLBACK (leave_notify_event), NULL);
|
|
g_signal_connect (drawing_area, "proximity_out_event",
|
|
G_CALLBACK (proximity_out_event), NULL);
|
|
|
|
event_mask = GDK_EXPOSURE_MASK |
|
|
GDK_LEAVE_NOTIFY_MASK |
|
|
GDK_BUTTON_PRESS_MASK |
|
|
GDK_KEY_PRESS_MASK |
|
|
GDK_POINTER_MOTION_MASK |
|
|
GDK_PROXIMITY_OUT_MASK;
|
|
|
|
gtk_widget_set_events (drawing_area, event_mask);
|
|
|
|
devices = gdk_seat_get_slaves (seat, GDK_SEAT_CAPABILITY_ALL_POINTING);
|
|
|
|
for (d = devices; d; d = d->next)
|
|
{
|
|
GdkDevice *device;
|
|
|
|
device = d->data;
|
|
gtk_widget_set_device_events (drawing_area, device, event_mask);
|
|
gdk_device_set_mode (device, GDK_MODE_SCREEN);
|
|
}
|
|
|
|
g_list_free (devices);
|
|
|
|
gtk_widget_set_can_focus (drawing_area, TRUE);
|
|
gtk_widget_grab_focus (drawing_area);
|
|
|
|
/* .. And create some buttons */
|
|
button = gtk_button_new_with_label ("Quit");
|
|
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
|
|
|
g_signal_connect_swapped (button, "clicked",
|
|
G_CALLBACK (gtk_widget_destroy),
|
|
window);
|
|
gtk_widget_show (button);
|
|
|
|
gtk_widget_show (window);
|
|
|
|
/* request all motion events */
|
|
gdk_win = gtk_widget_get_window (drawing_area);
|
|
gdk_window_set_event_compression (gdk_win, FALSE);
|
|
|
|
gtk_main ();
|
|
|
|
return 0;
|
|
}
|