diff options
-rw-r--r-- | panels/display/cc-display-panel.c | 843 | ||||
-rw-r--r-- | panels/display/meson.build | 1 | ||||
-rw-r--r-- | panels/display/scrollarea.c | 1511 | ||||
-rw-r--r-- | panels/display/scrollarea.h | 125 |
4 files changed, 1 insertions, 2479 deletions
diff --git a/panels/display/cc-display-panel.c b/panels/display/cc-display-panel.c index b36a5f9c1..37b71abfa 100644 --- a/panels/display/cc-display-panel.c +++ b/panels/display/cc-display-panel.c @@ -21,9 +21,6 @@ #include "cc-display-panel.h" #include <gtk/gtk.h> -#include "scrollarea.h" -#define GNOME_DESKTOP_USE_UNSTABLE_API -#include <libgnome-desktop/gnome-bg.h> #include <glib/gi18n.h> #include <stdlib.h> #include <gdesktop-enums.h> @@ -44,8 +41,6 @@ CC_PANEL_REGISTER (CcDisplayPanel, cc_display_panel) #define DISPLAY_PANEL_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_DISPLAY_PANEL, CcDisplayPanelPrivate)) -#define TOP_BAR_HEIGHT 5 - #define PANEL_PADDING 32 #define SECTION_PADDING 32 #define HEADING_PADDING 12 @@ -65,8 +60,7 @@ struct _CcDisplayPanelPrivate CcDisplayConfig *current_config; CcDisplayMonitor *current_output; - GnomeBG *background; - GnomeDesktopThumbnailFactory *thumbnail_factory; + CcDisplayArrangement *arrangement; guint focus_id; @@ -121,10 +115,6 @@ static void update_apply_button (CcDisplayPanel *panel); static void apply_current_configuration (CcDisplayPanel *self); -static void -on_area_paint (FooScrollArea *area, - cairo_t *cr, - gpointer data); static char * make_display_size_string (int width_mm, int height_mm); @@ -336,8 +326,6 @@ cc_display_panel_dispose (GObject *object) g_clear_object (&priv->manager); g_clear_object (&priv->current_config); g_clear_object (&priv->up_client); - g_clear_object (&priv->background); - g_clear_object (&priv->thumbnail_factory); g_clear_object (&priv->settings_color); g_clear_object (&priv->night_light_dialog); g_clear_object (&priv->main_size_group); @@ -393,150 +381,6 @@ set_current_output (CcDisplayPanel *panel, g_signal_emit (panel, panel_signals[CURRENT_OUTPUT], 0); } -static void -apply_rotation_to_geometry (CcDisplayMonitor *output, int *w, int *h) -{ - CcDisplayRotation rotation; - - rotation = cc_display_monitor_get_rotation (output); - if ((rotation == CC_DISPLAY_ROTATION_90) || (rotation == CC_DISPLAY_ROTATION_270)) - { - int tmp; - tmp = *h; - *h = *w; - *w = tmp; - } -} - -static void -get_geometry (CcDisplayMonitor *output, int *x, int *y, int *w, int *h) -{ - if (cc_display_monitor_is_active (output)) - { - cc_display_monitor_get_geometry (output, x, y, w, h); - } - else - { - cc_display_monitor_get_geometry (output, x, y, NULL, NULL); - cc_display_mode_get_resolution (cc_display_monitor_get_preferred_mode (output), - w, h); - } - - apply_rotation_to_geometry (output, w, h); -} - -static void -on_viewport_changed (FooScrollArea *scroll_area, - GdkRectangle *old_viewport, - GdkRectangle *new_viewport) -{ - foo_scroll_area_set_size (scroll_area, - new_viewport->width, - new_viewport->height); - - foo_scroll_area_invalidate (scroll_area); -} - -static void -paint_output (CcDisplayPanel *panel, - cairo_t *cr, - CcDisplayConfig *configuration, - CcDisplayMonitor *output, - gint num, - gint allocated_width, - gint allocated_height) -{ - CcDisplayPanelPrivate *priv = panel->priv; - GdkPixbuf *pixbuf; - gint x, y, width, height; - - get_geometry (output, NULL, NULL, &width, &height); - - x = y = 0; - - /* scale to fit allocation */ - if (width / (double) height < allocated_width / (double) allocated_height) - { - width = allocated_height * (width / (double) height); - height = allocated_height; - } - else - { - height = allocated_width * (height / (double) width); - width = allocated_width; - } - - - x = (allocated_width / 2.0) - (width / 2.0); - cairo_set_source_rgb (cr, 0, 0, 0); - cairo_rectangle (cr, x, y, width, height); - cairo_fill (cr); - - pixbuf = gnome_bg_create_thumbnail (priv->background, - priv->thumbnail_factory, - gdk_screen_get_default (), width, height); - - if (cc_display_monitor_is_primary (output) - || cc_display_config_is_cloning (configuration)) - { - y += TOP_BAR_HEIGHT; - height -= TOP_BAR_HEIGHT; - } - - if (pixbuf) - gdk_cairo_set_source_pixbuf (cr, pixbuf, x + 1, y + 1); - else - cairo_set_source_rgb (cr, 0.3, 0.3, 0.3); - cairo_rectangle (cr, x + 1, y + 1, width - 2, height - 2); - cairo_fill (cr); - - g_clear_object (&pixbuf); - - if (num > 0) - { - PangoLayout *layout; - gchar *number_str; - gdouble r = 3, r2 = r / 2.0, x1, y1, x2, y2; - PangoRectangle extents; - gdouble max_extent; - - number_str = g_strdup_printf ("<small>%d</small>", num); - layout = gtk_widget_create_pango_layout (GTK_WIDGET (panel), ""); - pango_layout_set_markup (layout, number_str, -1); - pango_layout_get_extents (layout, NULL, &extents); - g_free (number_str); - - cairo_set_source_rgba (cr, 0, 0, 0, 0.75); - max_extent = MAX ((extents.width - extents.x)/ PANGO_SCALE, - (extents.height - extents.y) / PANGO_SCALE); - - x += 5; - y += 5; - x1 = x; - x2 = x1 + max_extent + 1; - y1 = y; - y2 = y1 + max_extent + 1; - cairo_move_to (cr, x1 + r, y1); - cairo_line_to (cr, x2 - r, y1); - cairo_curve_to (cr, x2 - r2, y1, x2, y1 + r2, x2, y1 + r); - cairo_line_to (cr, x2, y2 - r); - cairo_curve_to (cr, x2, y2 - r2, x2 - r2, y2, x2 - r, y2); - cairo_line_to (cr, x1 + r, y2); - cairo_curve_to (cr, x1 + r2, y2, x1, y2 - r2, x1, y2 - r); - cairo_line_to (cr, x1, y1 + r); - cairo_curve_to (cr, x1, y1 + r2, x1 + r2, y1, x1 + r, y1); - cairo_fill (cr); - - cairo_set_source_rgb (cr, 1, 1, 1); - cairo_move_to (cr, - x + (max_extent / 2.0) - ((extents.width / PANGO_SCALE) / 2.0), - y + (max_extent / 2.0) - ((extents.height / PANGO_SCALE) / 2.0)); - pango_cairo_show_layout (cr, layout); - cairo_fill (cr); - g_object_unref (layout); - } -} - static GtkWidget * make_bin (void) { @@ -1281,26 +1125,6 @@ make_single_output_ui (CcDisplayPanel *panel) } static void -monitor_output_changes (GtkWidget *area, - CcDisplayPanel *panel) -{ - CcDisplayPanelPrivate *priv = panel->priv; - const gchar *signals[] = { "rotation", "mode", "primary", "active", "scale" }; - GList *outputs, *l; - guint i; - - outputs = cc_display_config_get_monitors (priv->current_config); - for (l = outputs; l; l = l->next) - { - CcDisplayMonitor *output = l->data; - for (i = 0; i < G_N_ELEMENTS (signals); ++i) - { - g_signal_connect_object (output, signals[i], G_CALLBACK (gtk_widget_queue_draw), - area, G_CONNECT_SWAPPED); - } - } -} - arrangement_notify_selected_ouptut_cb (CcDisplayPanel *panel, GParamSpec *pspec, CcDisplayArrangement *arr) @@ -2169,444 +1993,6 @@ on_screen_changed (CcDisplayPanel *panel) gtk_stack_set_visible_child_name (GTK_STACK (priv->stack), "error"); } -#define SPACE 15 -#define MARGIN 15 - -static void -get_total_size (CcDisplayPanel *self, int *total_w, int *total_h) -{ - GList *outputs, *l; - - *total_w = 0; - *total_h = 0; - - outputs = cc_display_config_get_monitors (self->priv->current_config); - for (l = outputs; l != NULL; l = l->next) - { - CcDisplayMonitor *output = l->data; - int w, h; - - if (!is_output_useful (output)) - continue; - - get_geometry (output, NULL, NULL, &w, &h); - - if (cc_display_config_is_layout_logical (self->priv->current_config)) - { - double scale = cc_display_monitor_get_scale (output); - w /= scale; - h /= scale; - } - - *total_w += w; - *total_h += h; - } -} - -static double -compute_scale (CcDisplayPanel *self, FooScrollArea *area) -{ - int available_w, available_h; - int total_w, total_h; - int n_monitors; - GdkRectangle viewport; - - foo_scroll_area_get_viewport (area, &viewport); - - get_total_size (self, &total_w, &total_h); - - n_monitors = count_useful_outputs (self); - - available_w = viewport.width - 2 * MARGIN - (n_monitors - 1) * SPACE; - available_h = viewport.height - 2 * MARGIN - (n_monitors - 1) * SPACE; - - return MIN ((double)available_w / total_w, (double)available_h / total_h); -} - -typedef struct Edge -{ - CcDisplayMonitor *output; - int x1, y1; - int x2, y2; -} Edge; - -typedef struct Snap -{ - Edge *snapper; /* Edge that should be snapped */ - Edge *snappee; - int dy, dx; -} Snap; - -static void -add_edge (CcDisplayMonitor *output, int x1, int y1, int x2, int y2, GArray *edges) -{ - Edge e; - - e.x1 = x1; - e.x2 = x2; - e.y1 = y1; - e.y2 = y2; - e.output = output; - - g_array_append_val (edges, e); -} - -static void -list_edges_for_output (CcDisplayMonitor *output, GArray *edges, gboolean should_scale) -{ - int x, y, w, h; - - get_geometry (output, &x, &y, &w, &h); - - if (should_scale) - { - double scale = cc_display_monitor_get_scale (output); - w /= scale; - h /= scale; - } - - /* Top, Bottom, Left, Right */ - add_edge (output, x, y, x + w, y, edges); - add_edge (output, x, y + h, x + w, y + h, edges); - add_edge (output, x, y, x, y + h, edges); - add_edge (output, x + w, y, x + w, y + h, edges); -} - -static void -list_edges (CcDisplayPanel *panel, GArray *edges) -{ - GList *outputs, *l; - gboolean should_scale; - - should_scale = cc_display_config_is_layout_logical (panel->priv->current_config); - outputs = cc_display_config_get_monitors (panel->priv->current_config); - - for (l = outputs; l != NULL; l = l->next) - { - CcDisplayMonitor *output = l->data; - - if (!is_output_useful (output)) - continue; - - list_edges_for_output (output, edges, should_scale); - } -} - -static gboolean -overlap (int s1, int e1, int s2, int e2) -{ - return (!(e1 < s2 || s1 >= e2)); -} - -static gboolean -horizontal_overlap (Edge *snapper, Edge *snappee) -{ - if (snapper->y1 != snapper->y2 || snappee->y1 != snappee->y2) - return FALSE; - - return overlap (snapper->x1, snapper->x2, snappee->x1, snappee->x2); -} - -static gboolean -vertical_overlap (Edge *snapper, Edge *snappee) -{ - if (snapper->x1 != snapper->x2 || snappee->x1 != snappee->x2) - return FALSE; - - return overlap (snapper->y1, snapper->y2, snappee->y1, snappee->y2); -} - -static void -add_snap (GArray *snaps, Snap snap) -{ - if (ABS (snap.dx) <= 200 || ABS (snap.dy) <= 200) - g_array_append_val (snaps, snap); -} - -static void -add_edge_snaps (Edge *snapper, Edge *snappee, GArray *snaps) -{ - Snap snap; - - snap.snapper = snapper; - snap.snappee = snappee; - - if (horizontal_overlap (snapper, snappee)) - { - snap.dx = 0; - snap.dy = snappee->y1 - snapper->y1; - - add_snap (snaps, snap); - } - else if (vertical_overlap (snapper, snappee)) - { - snap.dy = 0; - snap.dx = snappee->x1 - snapper->x1; - - add_snap (snaps, snap); - } - - /* Corner snaps */ - /* 1->1 */ - snap.dx = snappee->x1 - snapper->x1; - snap.dy = snappee->y1 - snapper->y1; - - add_snap (snaps, snap); - - /* 1->2 */ - snap.dx = snappee->x2 - snapper->x1; - snap.dy = snappee->y2 - snapper->y1; - - add_snap (snaps, snap); - - /* 2->2 */ - snap.dx = snappee->x2 - snapper->x2; - snap.dy = snappee->y2 - snapper->y2; - - add_snap (snaps, snap); - - /* 2->1 */ - snap.dx = snappee->x1 - snapper->x2; - snap.dy = snappee->y1 - snapper->y2; - - add_snap (snaps, snap); -} - -static void -list_snaps (CcDisplayMonitor *output, GArray *edges, GArray *snaps) -{ - int i; - - for (i = 0; i < edges->len; ++i) - { - Edge *output_edge = &(g_array_index (edges, Edge, i)); - - if (output_edge->output == output) - { - int j; - - for (j = 0; j < edges->len; ++j) - { - Edge *edge = &(g_array_index (edges, Edge, j)); - - if (edge->output != output) - add_edge_snaps (output_edge, edge, snaps); - } - } - } -} - -#if 0 -static void -print_edge (Edge *edge) -{ - g_debug ("(%d %d %d %d)", edge->x1, edge->y1, edge->x2, edge->y2); -} -#endif - -static gboolean -corner_on_edge (int x, int y, Edge *e) -{ - if (x == e->x1 && x == e->x2 && y >= e->y1 && y <= e->y2) - return TRUE; - - if (y == e->y1 && y == e->y2 && x >= e->x1 && x <= e->x2) - return TRUE; - - return FALSE; -} - -static gboolean -edges_align (Edge *e1, Edge *e2) -{ - if (corner_on_edge (e1->x1, e1->y1, e2)) - return TRUE; - - if (corner_on_edge (e2->x1, e2->y1, e1)) - return TRUE; - - return FALSE; -} - -static gboolean -output_is_aligned (CcDisplayMonitor *output, GArray *edges) -{ - gboolean result = FALSE; - int i; - - for (i = 0; i < edges->len; ++i) - { - Edge *output_edge = &(g_array_index (edges, Edge, i)); - - if (output_edge->output == output) - { - int j; - - for (j = 0; j < edges->len; ++j) - { - Edge *edge = &(g_array_index (edges, Edge, j)); - - /* We are aligned if an output edge matches - * an edge of another output - */ - if (edge->output != output_edge->output) - { - if (edges_align (output_edge, edge)) - { - result = TRUE; - goto done; - } - } - } - } - } - done: - - return result; -} - -static void -get_output_rect (CcDisplayMonitor *output, GdkRectangle *rect, gboolean should_scale) -{ - get_geometry (output, &rect->x, &rect->y, &rect->width, &rect->height); - if (should_scale) - { - double scale = cc_display_monitor_get_scale (output); - rect->height /= scale; - rect->width /= scale; - } -} - -static gboolean -output_overlaps (CcDisplayMonitor *output, CcDisplayPanel *panel) -{ - GdkRectangle output_rect; - GList *outputs, *l; - gboolean should_scale; - - g_assert (output != NULL); - - should_scale = cc_display_config_is_layout_logical (panel->priv->current_config); - get_output_rect (output, &output_rect, should_scale); - - outputs = cc_display_config_get_monitors (panel->priv->current_config); - for (l = outputs; l != NULL; l = l->next) - { - CcDisplayMonitor *o = l->data; - - if (!is_output_useful (o)) - continue; - - if (o != output) - { - GdkRectangle other_rect; - get_output_rect (o, &other_rect, should_scale); - if (gdk_rectangle_intersect (&output_rect, &other_rect, NULL)) - return TRUE; - } - } - - return FALSE; -} - -static gboolean -config_is_aligned (CcDisplayPanel *panel, GArray *edges) -{ - gboolean result = TRUE; - GList *outputs, *l; - - outputs = cc_display_config_get_monitors (panel->priv->current_config); - for (l = outputs; l != NULL; l = l->next) - { - CcDisplayMonitor *output = l->data; - - if (!is_output_useful (output)) - continue; - - if (!output_is_aligned (output, edges)) - return FALSE; - - if (output_overlaps (output, panel)) - return FALSE; - } - - return result; -} - -static gboolean -is_corner_snap (const Snap *s) -{ - return s->dx != 0 && s->dy != 0; -} - -static int -compare_snaps (gconstpointer v1, gconstpointer v2) -{ - const Snap *s1 = v1; - const Snap *s2 = v2; - int sv1 = MAX (ABS (s1->dx), ABS (s1->dy)); - int sv2 = MAX (ABS (s2->dx), ABS (s2->dy)); - int d; - - d = sv1 - sv2; - - /* This snapping algorithm is good enough for rock'n'roll, but - * this is probably a better: - * - * First do a horizontal/vertical snap, then - * with the new coordinates from that snap, - * do a corner snap. - * - * Right now, it's confusing that corner snapping - * depends on the distance in an axis that you can't actually see. - * - */ - if (d == 0) - { - if (is_corner_snap (s1) && !is_corner_snap (s2)) - return -1; - else if (is_corner_snap (s2) && !is_corner_snap (s1)) - return 1; - else - return 0; - } - else - { - return d; - } -} - -/* Sets a mouse cursor for a widget's window. As a hack, you can pass - * GDK_BLANK_CURSOR to mean "set the cursor to NULL" (i.e. reset the widget's - * window's cursor to its default). - */ -static void -set_cursor (GtkWidget *widget, GdkCursorType type) -{ - GdkCursor *cursor; - GdkWindow *window; - - if (type == GDK_BLANK_CURSOR) - cursor = NULL; - else - cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), type); - - window = gtk_widget_get_window (widget); - - if (window) - gdk_window_set_cursor (window, cursor); - - if (cursor) - g_object_unref (cursor); -} - -static void -grab_weak_ref_notify (gpointer area, - GObject *object) -{ - foo_scroll_area_end_grab (area, NULL); -} - static gboolean on_toplevel_key_press (GtkWidget *button, GdkEventKey *event) @@ -2694,225 +2080,6 @@ update_apply_button (CcDisplayPanel *panel) } static void -on_output_event (FooScrollArea *area, - FooScrollAreaEvent *event, - gpointer data) -{ - CcDisplayMonitor *output = data; - CcDisplayPanel *self = g_object_get_data (G_OBJECT (area), "panel"); - int n_monitors; - - if (event->type == FOO_DRAG_HOVER) - { - return; - } - if (event->type == FOO_DROP) - { - /* Activate new primary? */ - return; - } - - n_monitors = count_useful_outputs (self); - - /* If the mouse is inside the outputs, set the cursor to "you can move me". See - * on_canvas_event() for where we reset the cursor to the default if it - * exits the outputs' area. - */ - if (!cc_display_config_is_cloning (self->priv->current_config) && - n_monitors > 1) - set_cursor (GTK_WIDGET (area), GDK_FLEUR); - - if (event->type == FOO_BUTTON_PRESS) - { - GrabInfo *info; - - set_current_output (self, output); - - if (!cc_display_config_is_cloning (self->priv->current_config) && - n_monitors > 1) - { - int output_x, output_y; - cc_display_monitor_get_geometry (output, &output_x, &output_y, NULL, NULL); - - foo_scroll_area_begin_grab (area, on_output_event, data); - g_object_weak_ref (data, grab_weak_ref_notify, area); - - info = g_new0 (GrabInfo, 1); - info->grab_x = event->x; - info->grab_y = event->y; - info->output_x = output_x; - info->output_y = output_y; - - g_object_set_data (G_OBJECT (output), "grab-info", info); - } - foo_scroll_area_invalidate (area); - } - else - { - if (foo_scroll_area_is_grabbed (area)) - { - GrabInfo *info = g_object_get_data (G_OBJECT (output), "grab-info"); - double scale = compute_scale (self, area); - int old_x, old_y; - int new_x, new_y; - int i; - GArray *edges, *snaps, *new_edges; - - cc_display_monitor_get_geometry (output, &old_x, &old_y, NULL, NULL); - new_x = info->output_x + (event->x - info->grab_x) / scale; - new_y = info->output_y + (event->y - info->grab_y) / scale; - - cc_display_monitor_set_position (output, new_x, new_y); - - edges = g_array_new (TRUE, TRUE, sizeof (Edge)); - snaps = g_array_new (TRUE, TRUE, sizeof (Snap)); - new_edges = g_array_new (TRUE, TRUE, sizeof (Edge)); - - list_edges (self, edges); - list_snaps (output, edges, snaps); - - g_array_sort (snaps, compare_snaps); - - cc_display_monitor_set_position (output, old_x, old_y); - - for (i = 0; i < snaps->len; ++i) - { - Snap *snap = &(g_array_index (snaps, Snap, i)); - GArray *new_edges = g_array_new (TRUE, TRUE, sizeof (Edge)); - - cc_display_monitor_set_position (output, new_x + snap->dx, new_y + snap->dy); - - g_array_set_size (new_edges, 0); - list_edges (self, new_edges); - - if (config_is_aligned (self, new_edges)) - { - g_array_free (new_edges, TRUE); - break; - } - else - { - cc_display_monitor_set_position (output, info->output_x, info->output_y); - } - } - - g_array_free (new_edges, TRUE); - g_array_free (snaps, TRUE); - g_array_free (edges, TRUE); - - if (event->type == FOO_BUTTON_RELEASE) - { - foo_scroll_area_end_grab (area, event); - - g_free (g_object_get_data (G_OBJECT (output), "grab-info")); - g_object_set_data (G_OBJECT (output), "grab-info", NULL); - g_object_weak_unref (data, grab_weak_ref_notify, area); - update_apply_button (self); - -#if 0 - g_debug ("new position: %d %d %d %d", output->x, output->y, output->width, output->height); -#endif - } - - foo_scroll_area_invalidate (area); - } - } -} - -static void -on_canvas_event (FooScrollArea *area, - FooScrollAreaEvent *event, - gpointer data) -{ - /* If the mouse exits the outputs, reset the cursor to the default. See - * on_output_event() for where we set the cursor to the movement cursor if - * it is over one of the outputs. - */ - set_cursor (GTK_WIDGET (area), GDK_BLANK_CURSOR); -} - -static void -paint_background (FooScrollArea *area, - cairo_t *cr) -{ - GdkRectangle viewport; - - foo_scroll_area_get_viewport (area, &viewport); - - cairo_set_source_rgba (cr, 0, 0, 0, 0.0); - cairo_rectangle (cr, - viewport.x, viewport.y, - viewport.width, viewport.height); - foo_scroll_area_add_input_from_fill (area, cr, on_canvas_event, NULL); - cairo_fill (cr); -} - -static void -on_area_paint (FooScrollArea *area, - cairo_t *cr, - gpointer data) -{ - CcDisplayPanel *self = data; - GList *connected_outputs = NULL; - GList *list; - int total_w, total_h; - - paint_background (area, cr); - - if (!self->priv->current_config) - return; - - get_total_size (self, &total_w, &total_h); - - connected_outputs = cc_display_config_get_monitors (self->priv->current_config); - for (list = connected_outputs; list != NULL; list = list->next) - { - int w, h; - double scale = compute_scale (self, area); - gint x, y; - int output_x, output_y; - CcDisplayMonitor *output = list->data; - GdkRectangle viewport; - - if (!is_output_useful (output)) - continue; - - cairo_save (cr); - - foo_scroll_area_get_viewport (area, &viewport); - get_geometry (output, &output_x, &output_y, &w, &h); - if (cc_display_config_is_layout_logical (self->priv->current_config)) - { - double scale = cc_display_monitor_get_scale (output); - w /= scale; - h /= scale; - } - - viewport.height -= 2 * MARGIN; - viewport.width -= 2 * MARGIN; - - x = output_x * scale + MARGIN + (viewport.width - total_w * scale) / 2.0; - y = output_y * scale + MARGIN + (viewport.height - total_h * scale) / 2.0; - - - cairo_set_source_rgba (cr, 0, 0, 0, 0); - cairo_rectangle (cr, x, y, w * scale + 0.5, h * scale + 0.5); - foo_scroll_area_add_input_from_fill (area, cr, on_output_event, output); - cairo_fill (cr); - - cairo_translate (cr, x, y); - paint_output (self, cr, self->priv->current_config, output, - GPOINTER_TO_INT (g_object_get_data (G_OBJECT (output), "ui-number")), - w * scale, h * scale); - - cairo_restore (cr); - - if (cc_display_config_is_cloning (self->priv->current_config)) - break; - } -} - -static void apply_current_configuration (CcDisplayPanel *self) { GError *error = NULL; @@ -3310,7 +2477,6 @@ static void cc_display_panel_init (CcDisplayPanel *self) { CcDisplayPanelPrivate *priv; - GSettings *settings; g_autoptr (GtkCssProvider) provider = NULL; GtkWidget *bin; @@ -3333,13 +2499,6 @@ cc_display_panel_init (CcDisplayPanel *self) gtk_container_add (GTK_CONTAINER (self), priv->stack); gtk_widget_show_all (priv->stack); - settings = g_settings_new ("org.gnome.desktop.background"); - priv->background = gnome_bg_new (); - gnome_bg_load_from_preferences (priv->background, settings); - g_object_unref (settings); - - priv->thumbnail_factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL); - priv->night_light_dialog = cc_night_light_dialog_new (); priv->settings_color = g_settings_new ("org.gnome.settings-daemon.plugins.color"); diff --git a/panels/display/meson.build b/panels/display/meson.build index 57ff6539b..d00600112 100644 --- a/panels/display/meson.build +++ b/panels/display/meson.build @@ -26,7 +26,6 @@ sources = files( 'cc-display-config-manager.c', 'cc-night-light-dialog.c', 'cc-night-light-widget.c', - 'scrollarea.c', ) resource_data = files( diff --git a/panels/display/scrollarea.c b/panels/display/scrollarea.c deleted file mode 100644 index e71d2ece8..000000000 --- a/panels/display/scrollarea.c +++ /dev/null @@ -1,1511 +0,0 @@ -/* Copyright 2006, 2007, 2008, Soren Sandmann <sandmann@daimi.au.dk> - * - * 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/>. - */ - -#include "scrollarea.h" - -#include <gdk/gdk.h> - -G_DEFINE_TYPE_WITH_CODE (FooScrollArea, foo_scroll_area, GTK_TYPE_CONTAINER, - G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL)); - -static GtkWidgetClass *parent_class; - -typedef struct BackingStore BackingStore; - -typedef struct InputPath InputPath; -typedef struct InputRegion InputRegion; -typedef struct AutoScrollInfo AutoScrollInfo; - -struct InputPath -{ - gboolean is_stroke; - cairo_fill_rule_t fill_rule; - double line_width; - cairo_path_t *path; /* In canvas coordinates */ - - FooScrollAreaEventFunc func; - gpointer data; - - InputPath *next; -}; - -/* InputRegions are mutually disjoint */ -struct InputRegion -{ - /* the boundary of this area in canvas coordinates */ - cairo_region_t *region; - - InputPath *paths; -}; - -struct AutoScrollInfo -{ - int dx; - int dy; - int timeout_id; - int begin_x; - int begin_y; - double res_x; - double res_y; - GTimer *timer; -}; - -struct FooScrollAreaPrivate -{ - GdkWindow *input_window; - - int width; - int height; - - GtkAdjustment *hadj; - GtkAdjustment *vadj; - GtkScrollablePolicy hscroll_policy; - GtkScrollablePolicy vscroll_policy; - int x_offset; - int y_offset; - - int min_width; - int min_height; - - GPtrArray *input_regions; - - AutoScrollInfo *auto_scroll_info; - - /* During expose, this region is set to the region - * being exposed. At other times, it is NULL - * - * It is used for clipping of input areas - */ - InputRegion *current_input; - - gboolean grabbed; - FooScrollAreaEventFunc grab_func; - gpointer grab_data; - - cairo_surface_t *surface; - cairo_region_t *update_region; /* In canvas coordinates */ -}; - -enum - { - VIEWPORT_CHANGED, - PAINT, - INPUT, - LAST_SIGNAL, - }; - -enum { - PROP_0, - PROP_VADJUSTMENT, - PROP_HADJUSTMENT, - PROP_HSCROLL_POLICY, - PROP_VSCROLL_POLICY -}; - -static guint signals [LAST_SIGNAL] = { 0 }; - -static gboolean foo_scroll_area_draw (GtkWidget *widget, - cairo_t *cr); -static void foo_scroll_area_get_preferred_width (GtkWidget *widget, - gint *minimum, - gint *natural); -static void foo_scroll_area_get_preferred_height (GtkWidget *widget, - gint *minimum, - gint *natural); -static void foo_scroll_area_size_allocate (GtkWidget *widget, - GtkAllocation *allocation); -static void foo_scroll_area_set_hadjustment (FooScrollArea *scroll_area, - GtkAdjustment *hadjustment); -static void foo_scroll_area_set_vadjustment (FooScrollArea *scroll_area, - GtkAdjustment *vadjustment); -static void foo_scroll_area_realize (GtkWidget *widget); -static void foo_scroll_area_unrealize (GtkWidget *widget); -static void foo_scroll_area_map (GtkWidget *widget); -static void foo_scroll_area_unmap (GtkWidget *widget); -static gboolean foo_scroll_area_button_press (GtkWidget *widget, - GdkEventButton *event); -static gboolean foo_scroll_area_button_release (GtkWidget *widget, - GdkEventButton *event); -static gboolean foo_scroll_area_motion (GtkWidget *widget, - GdkEventMotion *event); - -static void -foo_scroll_area_map (GtkWidget *widget) -{ - FooScrollArea *area = FOO_SCROLL_AREA (widget); - - GTK_WIDGET_CLASS (parent_class)->map (widget); - - if (area->priv->input_window) - gdk_window_show (area->priv->input_window); -} - -static void -foo_scroll_area_unmap (GtkWidget *widget) -{ - FooScrollArea *area = FOO_SCROLL_AREA (widget); - - if (area->priv->input_window) - gdk_window_hide (area->priv->input_window); - - GTK_WIDGET_CLASS (parent_class)->unmap (widget); -} - -static void -foo_scroll_area_finalize (GObject *object) -{ - FooScrollArea *scroll_area = FOO_SCROLL_AREA (object); - - g_object_unref (scroll_area->priv->hadj); - g_object_unref (scroll_area->priv->vadj); - - g_ptr_array_free (scroll_area->priv->input_regions, TRUE); - - g_free (scroll_area->priv); - - G_OBJECT_CLASS (foo_scroll_area_parent_class)->finalize (object); -} - -static void -foo_scroll_area_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - FooScrollArea *scroll_area = FOO_SCROLL_AREA (object); - - switch (property_id) - { - case PROP_VADJUSTMENT: - g_value_set_object (value, &scroll_area->priv->vadj); - break; - case PROP_HADJUSTMENT: - g_value_set_object (value, &scroll_area->priv->hadj); - break; - case PROP_HSCROLL_POLICY: - g_value_set_enum (value, scroll_area->priv->hscroll_policy); - break; - case PROP_VSCROLL_POLICY: - g_value_set_enum (value, scroll_area->priv->vscroll_policy); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } -} - -static void -foo_scroll_area_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - FooScrollArea *scroll_area = FOO_SCROLL_AREA (object); - - switch (property_id) { - case PROP_VADJUSTMENT: - foo_scroll_area_set_vadjustment (FOO_SCROLL_AREA (object), g_value_get_object (value)); - break; - case PROP_HADJUSTMENT: - foo_scroll_area_set_hadjustment (FOO_SCROLL_AREA (object), g_value_get_object (value)); - break; - case PROP_HSCROLL_POLICY: - scroll_area->priv->hscroll_policy = g_value_get_enum (value); - break; - case PROP_VSCROLL_POLICY: - scroll_area->priv->vscroll_policy = g_value_get_enum (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } -} - -static void -foo_scroll_area_class_init (FooScrollAreaClass *class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (class); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); - - object_class->finalize = foo_scroll_area_finalize; - object_class->set_property = foo_scroll_area_set_property; - object_class->get_property = foo_scroll_area_get_property; - - widget_class->get_preferred_width = foo_scroll_area_get_preferred_width; - widget_class->get_preferred_height = foo_scroll_area_get_preferred_height; - widget_class->draw = foo_scroll_area_draw; - widget_class->size_allocate = foo_scroll_area_size_allocate; - widget_class->realize = foo_scroll_area_realize; - widget_class->unrealize = foo_scroll_area_unrealize; - widget_class->button_press_event = foo_scroll_area_button_press; - widget_class->button_release_event = foo_scroll_area_button_release; - widget_class->motion_notify_event = foo_scroll_area_motion; - widget_class->map = foo_scroll_area_map; - widget_class->unmap = foo_scroll_area_unmap; - - parent_class = g_type_class_peek_parent (class); - - /* Scrollable interface properties */ - g_object_class_override_property (object_class, PROP_HADJUSTMENT, "hadjustment"); - g_object_class_override_property (object_class, PROP_VADJUSTMENT, "vadjustment"); - g_object_class_override_property (object_class, PROP_HSCROLL_POLICY, "hscroll-policy"); - g_object_class_override_property (object_class, PROP_VSCROLL_POLICY, "vscroll-policy"); - - signals[VIEWPORT_CHANGED] = - g_signal_new ("viewport_changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (FooScrollAreaClass, - viewport_changed), - NULL, NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, 2, - GDK_TYPE_RECTANGLE, - GDK_TYPE_RECTANGLE); - - signals[PAINT] = - g_signal_new ("paint", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (FooScrollAreaClass, - paint), - NULL, NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, 1, - G_TYPE_POINTER); -} - -static GtkAdjustment * -new_adjustment (void) -{ - return GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)); -} - -static void -foo_scroll_area_init (FooScrollArea *scroll_area) -{ - GtkWidget *widget; - - widget = GTK_WIDGET (scroll_area); - - gtk_widget_set_has_window (widget, FALSE); - gtk_widget_set_redraw_on_allocate (widget, FALSE); - - scroll_area->priv = g_new0 (FooScrollAreaPrivate, 1); - scroll_area->priv->width = 0; - scroll_area->priv->height = 0; - scroll_area->priv->hadj = g_object_ref_sink (new_adjustment()); - scroll_area->priv->vadj = g_object_ref_sink (new_adjustment()); - scroll_area->priv->x_offset = 0.0; - scroll_area->priv->y_offset = 0.0; - scroll_area->priv->min_width = 0; - scroll_area->priv->min_height = 0; - scroll_area->priv->auto_scroll_info = NULL; - scroll_area->priv->input_regions = g_ptr_array_new (); - scroll_area->priv->surface = NULL; - scroll_area->priv->update_region = cairo_region_create (); -} - -typedef struct -{ - double x1, y1, x2, y2; -} Box; - -static void -input_path_free_list (InputPath *paths) -{ - if (!paths) - return; - - input_path_free_list (paths->next); - cairo_path_destroy (paths->path); - g_free (paths); -} - -static void -input_region_free (InputRegion *region) -{ - input_path_free_list (region->paths); - cairo_region_destroy (region->region); - - g_free (region); -} - -static void -get_viewport (FooScrollArea *scroll_area, - GdkRectangle *viewport) -{ - GtkAllocation allocation; - GtkWidget *widget = GTK_WIDGET (scroll_area); - - gtk_widget_get_allocation (widget, &allocation); - - viewport->x = scroll_area->priv->x_offset; - viewport->y = scroll_area->priv->y_offset; - viewport->width = allocation.width; - viewport->height = allocation.height; -} - -static void -allocation_to_canvas (FooScrollArea *area, - int *x, - int *y) -{ - *x += area->priv->x_offset; - *y += area->priv->y_offset; -} - -static void -clear_exposed_input_region (FooScrollArea *area, - cairo_region_t *exposed) /* in canvas coordinates */ -{ - int i; - cairo_region_t *viewport; - GdkRectangle allocation; - - gtk_widget_get_allocation (GTK_WIDGET (area), &allocation); - allocation.x = 0; - allocation.y = 0; - allocation_to_canvas (area, &allocation.x, &allocation.y); - - viewport = cairo_region_create_rectangle (&allocation); - cairo_region_subtract (viewport, exposed); - - for (i = 0; i < area->priv->input_regions->len; ++i) - { - InputRegion *region = area->priv->input_regions->pdata[i]; - - cairo_region_intersect (region->region, viewport); - - if (cairo_region_is_empty (region->region)) - { - input_region_free (region); - g_ptr_array_remove_index_fast (area->priv->input_regions, i--); - } - } - - cairo_region_destroy (viewport); -} - -/* taken from mutter */ -static void -setup_background_cr (GdkWindow *window, cairo_t *cr, int x_offset, int y_offset) -{ - GdkWindow *parent = gdk_window_get_parent (window); - cairo_pattern_t *bg_pattern; - - bg_pattern = gdk_window_get_background_pattern (window); - if (bg_pattern == NULL && parent) - { - gint window_x, window_y; - - gdk_window_get_position (window, &window_x, &window_y); - setup_background_cr (parent, cr, x_offset + window_x, y_offset + window_y); - } - else if (bg_pattern) - { - cairo_translate (cr, - x_offset, - y_offset); - cairo_set_source (cr, bg_pattern); - cairo_translate (cr, x_offset, y_offset); - } -} - -static void -initialize_background (GtkWidget *widget, - cairo_t *cr) -{ - setup_background_cr (gtk_widget_get_window (widget), cr, 0, 0); - - cairo_paint (cr); -} - -static gboolean -foo_scroll_area_draw (GtkWidget *widget, - cairo_t *cr) -{ - FooScrollArea *scroll_area = FOO_SCROLL_AREA (widget); - cairo_region_t *region; - GtkAllocation widget_allocation; - - /* Note that this function can be called at a time - * where the adj->value is different from x_offset. - * Ie., the GtkScrolledWindow changed the adj->value - * without emitting the value_changed signal. - * - * Hence we must always use the value we got - * the last time the signal was emitted, ie., - * priv->{x,y}_offset. - */ - - /* Setup input areas */ - clear_exposed_input_region (scroll_area, scroll_area->priv->update_region); - - scroll_area->priv->current_input = g_new0 (InputRegion, 1); - scroll_area->priv->current_input->region = cairo_region_copy (scroll_area->priv->update_region); - scroll_area->priv->current_input->paths = NULL; - g_ptr_array_add (scroll_area->priv->input_regions, - scroll_area->priv->current_input); - - region = scroll_area->priv->update_region; - scroll_area->priv->update_region = cairo_region_create (); - - initialize_background (widget, cr); - - g_signal_emit (widget, signals[PAINT], 0, cr); - - scroll_area->priv->current_input = NULL; - - gtk_widget_get_allocation (widget, &widget_allocation); - - /* Finally draw the backing surface */ - cairo_set_source_surface (cr, scroll_area->priv->surface, - widget_allocation.x, widget_allocation.y); - cairo_fill (cr); - - cairo_region_destroy (region); - - return TRUE; -} - -void -foo_scroll_area_get_viewport (FooScrollArea *scroll_area, - GdkRectangle *viewport) -{ - g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area)); - - if (!viewport) - return; - - get_viewport (scroll_area, viewport); -} - -static void -process_event (FooScrollArea *scroll_area, - FooScrollAreaEventType input_type, - int x, - int y); - -static void -emit_viewport_changed (FooScrollArea *scroll_area, - GdkRectangle *new_viewport, - GdkRectangle *old_viewport) -{ - int px, py; - g_signal_emit (scroll_area, signals[VIEWPORT_CHANGED], 0, - new_viewport, old_viewport); - - if (scroll_area->priv->input_window == NULL) - return; - - gdk_window_get_device_position (scroll_area->priv->input_window, - gdk_device_manager_get_client_pointer (gdk_display_get_device_manager (gdk_display_get_default ())), - &px, &py, NULL); - -#if 0 - g_print ("procc\n"); -#endif - - process_event (scroll_area, FOO_MOTION, px, py); -} - -static void -clamp_adjustment (GtkAdjustment *adj) -{ - if (gtk_adjustment_get_upper (adj) >= gtk_adjustment_get_page_size (adj)) - gtk_adjustment_set_value (adj, CLAMP (gtk_adjustment_get_value (adj), 0.0, - gtk_adjustment_get_upper (adj) - - gtk_adjustment_get_page_size (adj))); - else - gtk_adjustment_set_value (adj, 0.0); - - gtk_adjustment_changed (adj); -} - -static gboolean -set_adjustment_values (FooScrollArea *scroll_area) -{ - GtkAllocation allocation; - - GtkAdjustment *hadj = scroll_area->priv->hadj; - GtkAdjustment *vadj = scroll_area->priv->vadj; - - /* Horizontal */ - gtk_widget_get_allocation (GTK_WIDGET (scroll_area), &allocation); - g_object_freeze_notify (G_OBJECT (hadj)); - gtk_adjustment_set_page_size (hadj, allocation.width); - gtk_adjustment_set_step_increment (hadj, 0.1 * allocation.width); - gtk_adjustment_set_page_increment (hadj, 0.9 * allocation.width); - gtk_adjustment_set_lower (hadj, 0.0); - gtk_adjustment_set_upper (hadj, scroll_area->priv->width); - g_object_thaw_notify (G_OBJECT (hadj)); - - /* Vertical */ - g_object_freeze_notify (G_OBJECT (vadj)); - gtk_adjustment_set_page_size (vadj, allocation.height); - gtk_adjustment_set_step_increment (vadj, 0.1 * allocation.height); - gtk_adjustment_set_page_increment (vadj, 0.9 * allocation.height); - gtk_adjustment_set_lower (vadj, 0.0); - gtk_adjustment_set_upper (vadj, scroll_area->priv->height); - g_object_thaw_notify (G_OBJECT (vadj)); - - clamp_adjustment (hadj); - clamp_adjustment (vadj); - - return TRUE; -} - -static void -foo_scroll_area_realize (GtkWidget *widget) -{ - FooScrollArea *area = FOO_SCROLL_AREA (widget); - GdkWindowAttr attributes; - GtkAllocation widget_allocation; - GdkWindow *window; - gint attributes_mask; - cairo_t *cr; - - gtk_widget_get_allocation (widget, &widget_allocation); - gtk_widget_set_realized (widget, TRUE); - - attributes.window_type = GDK_WINDOW_CHILD; - attributes.x = widget_allocation.x; - attributes.y = widget_allocation.y; - attributes.width = widget_allocation.width; - attributes.height = widget_allocation.height; - attributes.wclass = GDK_INPUT_ONLY; - attributes.event_mask = gtk_widget_get_events (widget); - attributes.event_mask |= (GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_BUTTON1_MOTION_MASK | - GDK_BUTTON2_MOTION_MASK | - GDK_BUTTON3_MOTION_MASK | - GDK_POINTER_MOTION_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK); - - attributes_mask = GDK_WA_X | GDK_WA_Y; - - window = gtk_widget_get_parent_window (widget); - gtk_widget_set_window (widget, window); - g_object_ref (window); - - area->priv->input_window = gdk_window_new (window, - &attributes, attributes_mask); - - cr = gdk_cairo_create (gtk_widget_get_window (widget)); - area->priv->surface = cairo_surface_create_similar (cairo_get_target (cr), - CAIRO_CONTENT_COLOR, - widget_allocation.width, - widget_allocation.height); - cairo_destroy (cr); - - gdk_window_set_user_data (area->priv->input_window, area); -} - -static void -foo_scroll_area_unrealize (GtkWidget *widget) -{ - FooScrollArea *area = FOO_SCROLL_AREA (widget); - - if (area->priv->input_window) - { - gdk_window_set_user_data (area->priv->input_window, NULL); - gdk_window_destroy (area->priv->input_window); - area->priv->input_window = NULL; - } - - GTK_WIDGET_CLASS (parent_class)->unrealize (widget); -} - -static cairo_surface_t * -create_new_surface (GtkWidget *widget, - cairo_surface_t *old) -{ - GtkAllocation widget_allocation; - cairo_surface_t *new; - cairo_t *cr; - - gtk_widget_get_allocation (widget, &widget_allocation); - cr = gdk_cairo_create (gtk_widget_get_window (widget)); - new = cairo_surface_create_similar (cairo_get_target (cr), - CAIRO_CONTENT_COLOR, - widget_allocation.width, - widget_allocation.height); - cairo_destroy (cr); - - /* Unfortunately we don't know in which direction we were resized, - * so we just assume we were dragged from the south-east corner. - * - * Although, maybe we could get the root coordinates of the input-window? - * That might just work, actually. We need to make sure metacity uses - * static gravity for the window before this will be useful. - */ - cr = cairo_create (new); - cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); - cairo_set_source_surface (cr, old, 0, 0); - cairo_paint (cr); - cairo_destroy (cr); - - return new; -} - -static void -allocation_to_canvas_region (FooScrollArea *area, - cairo_region_t *region) -{ - cairo_region_translate (region, area->priv->x_offset, area->priv->y_offset); -} - -static void -_cairo_region_xor (cairo_region_t *dst, - const cairo_region_t *src) -{ - cairo_region_t *trb; - - trb = cairo_region_copy (src); - - cairo_region_subtract (trb, dst); - cairo_region_subtract (dst, src); - - cairo_region_union (dst, trb); - - cairo_region_destroy (trb); -} - -static void -foo_scroll_area_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) -{ - FooScrollArea *scroll_area = FOO_SCROLL_AREA (widget); - GdkRectangle new_viewport; - GdkRectangle old_viewport; - cairo_region_t *old_allocation; - cairo_region_t *invalid; - GtkAllocation widget_allocation; - - get_viewport (scroll_area, &old_viewport); - - gtk_widget_get_allocation (widget, &widget_allocation); - - old_allocation = cairo_region_create_rectangle (&widget_allocation); - cairo_region_translate (old_allocation, - -widget_allocation.x, -widget_allocation.y); - - invalid = cairo_region_create_rectangle (allocation); - cairo_region_translate (invalid, -allocation->x, -allocation->y); - _cairo_region_xor (invalid, old_allocation); - allocation_to_canvas_region (scroll_area, invalid); - foo_scroll_area_invalidate_region (scroll_area, invalid); - - cairo_region_destroy (old_allocation); - cairo_region_destroy (invalid); - - gtk_widget_set_allocation (widget, allocation); - - if (scroll_area->priv->input_window) - { - cairo_surface_t *new_surface; - - gdk_window_move_resize (scroll_area->priv->input_window, - allocation->x, allocation->y, - allocation->width, allocation->height); - - new_surface = create_new_surface (widget, scroll_area->priv->surface); - cairo_surface_destroy (scroll_area->priv->surface); - - scroll_area->priv->surface = new_surface; - } - - get_viewport (scroll_area, &new_viewport); - - emit_viewport_changed (scroll_area, &new_viewport, &old_viewport); -} - -static void -emit_input (FooScrollArea *scroll_area, - FooScrollAreaEventType type, - int x, - int y, - FooScrollAreaEventFunc func, - gpointer data) -{ - FooScrollAreaEvent event; - - if (!func) - return; - - event.type = type; - event.x = x; - event.y = y; - - func (scroll_area, &event, data); -} - -static void -process_event (FooScrollArea *scroll_area, - FooScrollAreaEventType input_type, - int x, - int y) -{ - GtkWidget *widget = GTK_WIDGET (scroll_area); - int i; - - allocation_to_canvas (scroll_area, &x, &y); - - if (scroll_area->priv->grabbed) - { - emit_input (scroll_area, input_type, x, y, - scroll_area->priv->grab_func, - scroll_area->priv->grab_data); - } - -#if 0 - g_print ("number of input regions: %d\n", scroll_area->priv->input_regions->len); -#endif - - for (i = 0; i < scroll_area->priv->input_regions->len; ++i) - { - InputRegion *region = scroll_area->priv->input_regions->pdata[i]; - -#if 0 - g_print ("region %d (looking for %d,%d) ", i, x, y); -#endif - - if (cairo_region_contains_point (region->region, x, y)) - { - InputPath *path; - - path = region->paths; - while (path) - { - cairo_t *cr; - gboolean inside; - - cr = gdk_cairo_create (gtk_widget_get_window (widget)); - cairo_set_fill_rule (cr, path->fill_rule); - cairo_set_line_width (cr, path->line_width); - cairo_append_path (cr, path->path); - - if (path->is_stroke) - inside = cairo_in_stroke (cr, x, y); - else - inside = cairo_in_fill (cr, x, y); - - cairo_destroy (cr); - - if (inside) - { - if (scroll_area->priv->grabbed) - { - emit_input (scroll_area, FOO_DRAG_HOVER, - x, y, - path->func, - path->data); - } - else - { - emit_input (scroll_area, input_type, - x, y, - path->func, - path->data); - } - return; - } - - path = path->next; - } - - /* Since the regions are all disjoint, no other region - * can match. Of course we could be clever and try and - * sort the regions, but so far I have been unable to - * make this loop show up on a profile. - */ - return; - } - } -} - -static void -process_gdk_event (FooScrollArea *scroll_area, - int x, - int y, - GdkEvent *event) -{ - FooScrollAreaEventType input_type; - - if (event->type == GDK_BUTTON_PRESS) - input_type = FOO_BUTTON_PRESS; - else if (event->type == GDK_BUTTON_RELEASE) - input_type = FOO_BUTTON_RELEASE; - else if (event->type == GDK_MOTION_NOTIFY) - input_type = FOO_MOTION; - else - return; - - process_event (scroll_area, input_type, x, y); -} - -static gboolean -foo_scroll_area_button_press (GtkWidget *widget, - GdkEventButton *event) -{ - FooScrollArea *area = FOO_SCROLL_AREA (widget); - - process_gdk_event (area, event->x, event->y, (GdkEvent *)event); - - return TRUE; -} - -static gboolean -foo_scroll_area_button_release (GtkWidget *widget, - GdkEventButton *event) -{ - FooScrollArea *area = FOO_SCROLL_AREA (widget); - - process_gdk_event (area, event->x, event->y, (GdkEvent *)event); - - return FALSE; -} - -static gboolean -foo_scroll_area_motion (GtkWidget *widget, - GdkEventMotion *event) -{ - FooScrollArea *area = FOO_SCROLL_AREA (widget); - - process_gdk_event (area, event->x, event->y, (GdkEvent *)event); - return TRUE; -} - -void -foo_scroll_area_set_size_fixed_y (FooScrollArea *scroll_area, - int width, - int height, - int old_y, - int new_y) -{ - scroll_area->priv->width = width; - scroll_area->priv->height = height; - -#if 0 - g_print ("diff: %d\n", new_y - old_y); -#endif - g_object_thaw_notify (G_OBJECT (scroll_area->priv->vadj)); - gtk_adjustment_set_value (scroll_area->priv->vadj, new_y); - - set_adjustment_values (scroll_area); - g_object_thaw_notify (G_OBJECT (scroll_area->priv->vadj)); -} - -void -foo_scroll_area_set_size (FooScrollArea *scroll_area, - int width, - int height) -{ - g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area)); - - /* FIXME: Default scroll algorithm should probably be to - * keep the same *area* outside the screen as before. - * - * For wrapper widgets that will do something roughly - * right. For widgets that don't change size, it - * will do the right thing. Except for idle-layouting - * widgets. - * - * Maybe there should be some generic support for those - * widgets. Can that even be done? - * - * Should we have a version of this function using - * fixed points? - */ - - scroll_area->priv->width = width; - scroll_area->priv->height = height; - - set_adjustment_values (scroll_area); -} - -static void -foo_scroll_area_get_preferred_width (GtkWidget *widget, - gint *minimum, - gint *natural) -{ - FooScrollArea *scroll_area = FOO_SCROLL_AREA (widget); - - if (minimum != NULL) { - *minimum = scroll_area->priv->min_width; - } - if (natural != NULL) { - *natural = scroll_area->priv->min_width; - } -} - -static void -foo_scroll_area_get_preferred_height (GtkWidget *widget, - gint *minimum, - gint *natural) -{ - FooScrollArea *scroll_area = FOO_SCROLL_AREA (widget); - - if (minimum != NULL) { - *minimum = scroll_area->priv->min_height; - } - if (natural != NULL) { - *natural = scroll_area->priv->min_height; - } -} - -static void -foo_scroll_area_scroll (FooScrollArea *area, - gint dx, - gint dy) -{ - GdkRectangle allocation; - GdkRectangle src_area; - GdkRectangle move_area; - cairo_region_t *invalid_region; - - gtk_widget_get_allocation (GTK_WIDGET (area), &allocation); - allocation.x = 0; - allocation.y = 0; - - src_area = allocation; - src_area.x -= dx; - src_area.y -= dy; - - invalid_region = cairo_region_create_rectangle (&allocation); - - if (gdk_rectangle_intersect (&allocation, &src_area, &move_area)) - { - cairo_region_t *move_region; - cairo_t *cr; - -#if 0 - g_print ("scrolling %d %d %d %d (%d %d)\n", - move_area.x, move_area.y, - move_area.width, move_area.height, - dx, dy); -#endif - cr = cairo_create (area->priv->surface); - - /* Cairo doesn't allow self-copies, so we do this little trick instead: - * 1) Clip so the group size is small. - * 2) Call push_group() which creates a temporary pixmap as a workaround - */ - gdk_cairo_rectangle (cr, &move_area); - cairo_clip (cr); - cairo_push_group (cr); - - cairo_set_source_surface (cr, area->priv->surface, dx, dy); - gdk_cairo_rectangle (cr, &move_area); - cairo_fill (cr); - - cairo_pop_group_to_source (cr); - cairo_paint (cr); - - cairo_destroy (cr); - - gtk_widget_queue_draw (GTK_WIDGET (area)); - - move_region = cairo_region_create_rectangle (&move_area); - cairo_region_translate (move_region, dx, dy); - cairo_region_subtract (invalid_region, move_region); - cairo_region_destroy (move_region); - } - - allocation_to_canvas_region (area, invalid_region); - - foo_scroll_area_invalidate_region (area, invalid_region); - - cairo_region_destroy (invalid_region); -} - -static void -foo_scrollbar_adjustment_changed (GtkAdjustment *adj, - FooScrollArea *scroll_area) -{ - GtkWidget *widget = GTK_WIDGET (scroll_area); - gint dx = 0; - gint dy = 0; - GdkRectangle old_viewport, new_viewport; - - get_viewport (scroll_area, &old_viewport); - - if (adj == scroll_area->priv->hadj) - { - /* FIXME: do we treat the offset as int or double, and, - * if int, how do we round? - */ - dx = (int)gtk_adjustment_get_value (adj) - scroll_area->priv->x_offset; - scroll_area->priv->x_offset = gtk_adjustment_get_value (adj); - } - else if (adj == scroll_area->priv->vadj) - { - dy = (int)gtk_adjustment_get_value (adj) - scroll_area->priv->y_offset; - scroll_area->priv->y_offset = gtk_adjustment_get_value (adj); - } - else - { - g_assert_not_reached (); - } - - if (gtk_widget_get_realized (widget)) - { - foo_scroll_area_scroll (scroll_area, -dx, -dy); - - //translate_input_regions (scroll_area, -dx, -dy); - - } - - get_viewport (scroll_area, &new_viewport); - - emit_viewport_changed (scroll_area, &new_viewport, &old_viewport); -} - -static void -set_one_adjustment (FooScrollArea *scroll_area, - GtkAdjustment *adjustment, - GtkAdjustment **location) -{ - g_return_if_fail (location != NULL); - - if (adjustment == *location) - return; - - if (!adjustment) - adjustment = new_adjustment (); - - g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment)); - - if (*location) - { - g_signal_handlers_disconnect_by_func ( - *location, foo_scrollbar_adjustment_changed, scroll_area); - - g_object_unref (*location); - } - - *location = adjustment; - - g_object_ref_sink (*location); - - g_signal_connect (*location, "value_changed", - G_CALLBACK (foo_scrollbar_adjustment_changed), - scroll_area); -} - -static void -foo_scroll_area_set_hadjustment (FooScrollArea *scroll_area, - GtkAdjustment *hadjustment) -{ - set_one_adjustment (scroll_area, hadjustment, &scroll_area->priv->hadj); - - set_adjustment_values (scroll_area); -} - -static void -foo_scroll_area_set_vadjustment (FooScrollArea *scroll_area, - GtkAdjustment *vadjustment) -{ - set_one_adjustment (scroll_area, vadjustment, &scroll_area->priv->vadj); - - set_adjustment_values (scroll_area); -} - -FooScrollArea * -foo_scroll_area_new (void) -{ - return g_object_new (FOO_TYPE_SCROLL_AREA, NULL); -} - -void -foo_scroll_area_set_min_size (FooScrollArea *scroll_area, - int min_width, - int min_height) -{ - scroll_area->priv->min_width = min_width; - scroll_area->priv->min_height = min_height; - - /* FIXME: think through invalidation. - * - * Goals: - no repainting everything on size_allocate(), - * - make sure input boxes are invalidated when - * needed - */ - gtk_widget_queue_resize (GTK_WIDGET (scroll_area)); -} - -static InputPath * -make_path (FooScrollArea *area, - cairo_t *cr, - gboolean is_stroke, - FooScrollAreaEventFunc func, - gpointer data) -{ - InputPath *path = g_new0 (InputPath, 1); - - path->is_stroke = is_stroke; - path->fill_rule = cairo_get_fill_rule (cr); - path->line_width = cairo_get_line_width (cr); - path->path = cairo_copy_path (cr); - path->func = func; - path->data = data; - path->next = area->priv->current_input->paths; - area->priv->current_input->paths = path; - return path; -} - -/* FIXME: we probably really want a - * - * foo_scroll_area_add_input_from_fill (area, cr, ...); - * and - * foo_scroll_area_add_input_from_stroke (area, cr, ...); - * as well. - */ -void -foo_scroll_area_add_input_from_fill (FooScrollArea *scroll_area, - cairo_t *cr, - FooScrollAreaEventFunc func, - gpointer data) -{ - g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area)); - g_return_if_fail (cr != NULL); - g_return_if_fail (scroll_area->priv->current_input); - - make_path (scroll_area, cr, FALSE, func, data); -} - -void -foo_scroll_area_add_input_from_stroke (FooScrollArea *scroll_area, - cairo_t *cr, - FooScrollAreaEventFunc func, - gpointer data) -{ - g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area)); - g_return_if_fail (cr != NULL); - g_return_if_fail (scroll_area->priv->current_input); - - make_path (scroll_area, cr, TRUE, func, data); -} - -void -foo_scroll_area_invalidate (FooScrollArea *scroll_area) -{ - GtkAllocation allocation; - GtkWidget *widget = GTK_WIDGET (scroll_area); - - gtk_widget_get_allocation (widget, &allocation); - foo_scroll_area_invalidate_rect (scroll_area, - scroll_area->priv->x_offset, scroll_area->priv->y_offset, - allocation.width, - allocation.height); -} - -static void -canvas_to_window (FooScrollArea *area, - cairo_region_t *region) -{ - GtkAllocation allocation; - GtkWidget *widget = GTK_WIDGET (area); - - gtk_widget_get_allocation (widget, &allocation); - cairo_region_translate (region, - -area->priv->x_offset + allocation.x, - -area->priv->y_offset + allocation.y); -} - -static void -window_to_canvas (FooScrollArea *area, - cairo_region_t *region) -{ - GtkAllocation allocation; - GtkWidget *widget = GTK_WIDGET (area); - - gtk_widget_get_allocation (widget, &allocation); - cairo_region_translate (region, - area->priv->x_offset - allocation.x, - area->priv->y_offset - allocation.y); -} - -void -foo_scroll_area_invalidate_region (FooScrollArea *area, - cairo_region_t *region) -{ - GtkWidget *widget; - - g_return_if_fail (FOO_IS_SCROLL_AREA (area)); - - widget = GTK_WIDGET (area); - - cairo_region_union (area->priv->update_region, region); - - if (gtk_widget_get_realized (widget)) - { - canvas_to_window (area, region); - - gdk_window_invalidate_region (gtk_widget_get_window (widget), - region, TRUE); - - window_to_canvas (area, region); - } -} - -void -foo_scroll_area_invalidate_rect (FooScrollArea *scroll_area, - int x, - int y, - int width, - int height) -{ - cairo_rectangle_int_t rect = { x, y, width, height }; - cairo_region_t *region; - - g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area)); - - region = cairo_region_create_rectangle (&rect); - - foo_scroll_area_invalidate_region (scroll_area, region); - - cairo_region_destroy (region); -} - -void -foo_scroll_area_begin_grab (FooScrollArea *scroll_area, - FooScrollAreaEventFunc func, - gpointer input_data) -{ - g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area)); - g_return_if_fail (!scroll_area->priv->grabbed); - - scroll_area->priv->grabbed = TRUE; - scroll_area->priv->grab_func = func; - scroll_area->priv->grab_data = input_data; - - /* FIXME: we should probably take a server grab */ - /* Also, maybe there should be support for setting the grab cursor */ -} - -void -foo_scroll_area_end_grab (FooScrollArea *scroll_area, - FooScrollAreaEvent *event) -{ - g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area)); - - scroll_area->priv->grabbed = FALSE; - scroll_area->priv->grab_func = NULL; - scroll_area->priv->grab_data = NULL; - - if (event != NULL) - process_event (scroll_area, FOO_DROP, event->x, event->y); -} - -gboolean -foo_scroll_area_is_grabbed (FooScrollArea *scroll_area) -{ - return scroll_area->priv->grabbed; -} - -void -foo_scroll_area_set_viewport_pos (FooScrollArea *scroll_area, - int x, - int y) -{ - g_object_freeze_notify (G_OBJECT (scroll_area->priv->hadj)); - g_object_freeze_notify (G_OBJECT (scroll_area->priv->vadj)); - gtk_adjustment_set_value (scroll_area->priv->hadj, x); - gtk_adjustment_set_value (scroll_area->priv->vadj, y); - - set_adjustment_values (scroll_area); - g_object_thaw_notify (G_OBJECT (scroll_area->priv->hadj)); - g_object_thaw_notify (G_OBJECT (scroll_area->priv->vadj)); -} - -static gboolean -rect_contains (const GdkRectangle *rect, int x, int y) -{ - return (x >= rect->x && - y >= rect->y && - x < rect->x + rect->width && - y < rect->y + rect->height); -} - -static void -stop_scrolling (FooScrollArea *area) -{ -#if 0 - g_print ("stop scrolling\n"); -#endif - if (area->priv->auto_scroll_info) - { - g_source_remove (area->priv->auto_scroll_info->timeout_id); - g_timer_destroy (area->priv->auto_scroll_info->timer); - g_free (area->priv->auto_scroll_info); - - area->priv->auto_scroll_info = NULL; - } -} - -static gboolean -scroll_idle (gpointer data) -{ - GdkRectangle viewport, new_viewport; - FooScrollArea *area = data; - AutoScrollInfo *info = area->priv->auto_scroll_info; - int new_x, new_y; - double elapsed; - - get_viewport (area, &viewport); - -#if 0 - g_print ("old info: %d %d\n", info->dx, info->dy); - - g_print ("timeout (%d %d)\n", dx, dy); -#endif - -#if 0 - g_print ("new info %d %d\n", info->dx, info->dy); -#endif - - elapsed = g_timer_elapsed (info->timer, NULL); - - info->res_x = elapsed * info->dx / 0.2; - info->res_y = elapsed * info->dy / 0.2; - -#if 0 - g_print ("%f %f\n", info->res_x, info->res_y); -#endif - - new_x = viewport.x + info->res_x; - new_y = viewport.y + info->res_y; - -#if 0 - g_print ("%f\n", elapsed * (info->dx / 0.2)); -#endif - -#if 0 - g_print ("new_x, new_y\n: %d %d\n", new_x, new_y); -#endif - - foo_scroll_area_set_viewport_pos (area, new_x, new_y); -#if 0 - viewport.x + info->dx, - viewport.y + info->dy); -#endif - -get_viewport (area, &new_viewport); - -if (viewport.x == new_viewport.x && - viewport.y == new_viewport.y && - (info->res_x > 1.0 || - info->res_y > 1.0 || - info->res_x < -1.0 || - info->res_y < -1.0)) - { - stop_scrolling (area); - - /* stop scrolling if it didn't have an effect */ - return FALSE; - } - -return TRUE; -} - -static void -ensure_scrolling (FooScrollArea *area, - int dx, - int dy) -{ - if (!area->priv->auto_scroll_info) - { -#if 0 - g_print ("start scrolling\n"); -#endif - area->priv->auto_scroll_info = g_new0 (AutoScrollInfo, 1); - area->priv->auto_scroll_info->timeout_id = - g_idle_add (scroll_idle, area); - area->priv->auto_scroll_info->timer = g_timer_new (); - } - -#if 0 - g_print ("setting scrolling to %d %d\n", dx, dy); -#endif - -#if 0 - g_print ("dx, dy: %d %d\n", dx, dy); -#endif - - area->priv->auto_scroll_info->dx = dx; - area->priv->auto_scroll_info->dy = dy; -} - -void -foo_scroll_area_auto_scroll (FooScrollArea *scroll_area, - FooScrollAreaEvent *event) -{ - GdkRectangle viewport; - - get_viewport (scroll_area, &viewport); - - if (rect_contains (&viewport, event->x, event->y)) - { - stop_scrolling (scroll_area); - } - else - { - int dx, dy; - - dx = dy = 0; - - if (event->y < viewport.y) - { - dy = event->y - viewport.y; - dy = MIN (dy + 2, 0); - } - else if (event->y >= viewport.y + viewport.height) - { - dy = event->y - (viewport.y + viewport.height - 1); - dy = MAX (dy - 2, 0); - } - - if (event->x < viewport.x) - { - dx = event->x - viewport.x; - dx = MIN (dx + 2, 0); - } - else if (event->x >= viewport.x + viewport.width) - { - dx = event->x - (viewport.x + viewport.width - 1); - dx = MAX (dx - 2, 0); - } - -#if 0 - g_print ("dx, dy: %d %d\n", dx, dy); -#endif - - ensure_scrolling (scroll_area, dx, dy); - } -} - -void -foo_scroll_area_begin_auto_scroll (FooScrollArea *scroll_area) -{ - /* noop for now */ -} - -void -foo_scroll_area_end_auto_scroll (FooScrollArea *scroll_area) -{ - stop_scrolling (scroll_area); -} - diff --git a/panels/display/scrollarea.h b/panels/display/scrollarea.h deleted file mode 100644 index b097d3d4c..000000000 --- a/panels/display/scrollarea.h +++ /dev/null @@ -1,125 +0,0 @@ -/* Copyright 2006, 2007, 2008, Soren Sandmann <sandmann@daimi.au.dk> - * - * 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/>. - */ -#include <cairo.h> -#include <gtk/gtk.h> - -#define FOO_TYPE_SCROLL_AREA (foo_scroll_area_get_type ()) -#define FOO_SCROLL_AREA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FOO_TYPE_SCROLL_AREA, FooScrollArea)) -#define FOO_SCROLL_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), FOO_TYPE_SCROLL_AREA, FooScrollAreaClass)) -#define FOO_IS_SCROLL_AREA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FOO_TYPE_SCROLL_AREA)) -#define FOO_IS_SCROLL_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), FOO_TYPE_SCROLL_AREA)) -#define FOO_SCROLL_AREA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), FOO_TYPE_SCROLL_AREA, FooScrollAreaClass)) - -typedef struct FooScrollArea FooScrollArea; -typedef struct FooScrollAreaClass FooScrollAreaClass; -typedef struct FooScrollAreaPrivate FooScrollAreaPrivate; -typedef struct FooScrollAreaEvent FooScrollAreaEvent; - -typedef enum - { - FOO_BUTTON_PRESS, - FOO_BUTTON_RELEASE, - FOO_DRAG_HOVER, - FOO_DROP, - FOO_MOTION - } FooScrollAreaEventType; - -struct FooScrollAreaEvent -{ - FooScrollAreaEventType type; - int x; - int y; -}; - -typedef void (* FooScrollAreaEventFunc) (FooScrollArea *area, - FooScrollAreaEvent *event, - gpointer data); - -struct FooScrollArea -{ - GtkContainer parent_instance; - - FooScrollAreaPrivate *priv; -}; - -struct FooScrollAreaClass -{ - GtkContainerClass parent_class; - - void (*set_scroll_adjustments) (FooScrollArea *scroll_area, - GtkAdjustment *hadjustment, - GtkAdjustment *vadjustment); - - void (*viewport_changed) (FooScrollArea *scroll_area, - GdkRectangle *old_viewport, - GdkRectangle *new_viewport); - - void (*paint) (FooScrollArea *scroll_area, - cairo_t *cr, - GdkRectangle *extents, - cairo_region_t *region); -}; - -GType foo_scroll_area_get_type (void); - -FooScrollArea *foo_scroll_area_new (void); - -/* Set the requisition for the widget. */ -void foo_scroll_area_set_min_size (FooScrollArea *scroll_area, - int min_width, - int min_height); - -/* Set how much of the canvas can be scrolled into view */ -void foo_scroll_area_set_size (FooScrollArea *scroll_area, - int width, - int height); -void foo_scroll_area_set_size_fixed_y (FooScrollArea *scroll_area, - int width, - int height, - int old_y, - int new_y); -void foo_scroll_area_set_viewport_pos (FooScrollArea *scroll_area, - int x, - int y); -void foo_scroll_area_get_viewport (FooScrollArea *scroll_area, - GdkRectangle *viewport); -void foo_scroll_area_add_input_from_stroke (FooScrollArea *scroll_area, - cairo_t *cr, - FooScrollAreaEventFunc func, - gpointer data); -void foo_scroll_area_add_input_from_fill (FooScrollArea *scroll_area, - cairo_t *cr, - FooScrollAreaEventFunc func, - gpointer data); -void foo_scroll_area_invalidate_region (FooScrollArea *area, - cairo_region_t *region); -void foo_scroll_area_invalidate (FooScrollArea *scroll_area); -void foo_scroll_area_invalidate_rect (FooScrollArea *scroll_area, - int x, - int y, - int width, - int height); -void foo_scroll_area_begin_grab (FooScrollArea *scroll_area, - FooScrollAreaEventFunc func, - gpointer input_data); -void foo_scroll_area_end_grab (FooScrollArea *scroll_area, - FooScrollAreaEvent *event); -gboolean foo_scroll_area_is_grabbed (FooScrollArea *scroll_area); - -void foo_scroll_area_begin_auto_scroll (FooScrollArea *scroll_area); -void foo_scroll_area_auto_scroll (FooScrollArea *scroll_area, - FooScrollAreaEvent *event); -void foo_scroll_area_end_auto_scroll (FooScrollArea *scroll_area); |