1 /*
2 * overviewscintilla.c - This file is part of the Geany Overview plugin
3 *
4 * Copyright (c) 2015 Matthew Brush <mbrush@codebrainz.ca>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 *
21 */
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include "overviewscintilla.h"
28 #include "overviewplugin.h"
29 #include <string.h>
30
31 #define OVERVIEW_SCINTILLA_CURSOR GDK_ARROW
32 #define OVERVIEW_SCINTILLA_CURSOR_CLICK GDK_ARROW
33 #define OVERVIEW_SCINTILLA_CURSOR_SCROLL GDK_SB_V_DOUBLE_ARROW
34 #define OVERVIEW_SCINTILLA_ZOOM_MIN -100
35 #define OVERVIEW_SCINTILLA_ZOOM_MAX 100
36 #define OVERVIEW_SCINTILLA_ZOOM_DEF -20
37 #define OVERVIEW_SCINTILLA_WIDTH_MIN 16
38 #define OVERVIEW_SCINTILLA_WIDTH_MAX 512
39 #define OVERVIEW_SCINTILLA_WIDTH_DEF 120
40 #define OVERVIEW_SCINTILLA_SCROLL_LINES 1
41
42 #ifndef SC_MAX_MARGIN
43 # define SC_MAX_MARGIN 4
44 #endif
45
46 #define sci_send(sci, msg, wParam, lParam) \
47 scintilla_send_message (SCINTILLA (sci), SCI_##msg, (uptr_t)(wParam), (sptr_t)(lParam))
48
49 static const OverviewColor def_overlay_color = { 0.0, 0.0, 0.0, 0.25 };
50 static const OverviewColor def_overlay_outline_color = { 0.0, 0.0, 0.0, 0.0 };
51
52 enum
53 {
54 PROP_0,
55 PROP_SCINTILLA,
56 PROP_CURSOR,
57 PROP_VISIBLE_RECT,
58 PROP_WIDTH,
59 PROP_ZOOM,
60 PROP_SHOW_TOOLTIP,
61 PROP_OVERLAY_ENABLED,
62 PROP_OVERLAY_COLOR,
63 PROP_OVERLAY_OUTLINE_COLOR,
64 PROP_OVERLAY_INVERTED,
65 PROP_DOUBLE_BUFFERED,
66 PROP_SCROLL_LINES,
67 PROP_SHOW_SCROLLBAR,
68 N_PROPERTIES,
69 };
70
71 struct OverviewScintilla_
72 {
73 ScintillaObject parent;
74 ScintillaObject *sci; // source scintilla
75 GtkWidget *canvas; // internal GtkDrawingArea of scintilla
76 GdkCursorType cursor; // the chosen mouse cursor to use over the scintilla
77 GdkCursorType active_cursor; // the cursor to draw
78 GdkRectangle visible_rect; // visible region rectangle
79 guint width; // width of the overview
80 gint zoom; // zoom level of scintilla
81 gboolean show_tooltip; // whether tooltip shown on hover
82 gboolean overlay_enabled; // whether the visible overlay is drawn
83 OverviewColor overlay_color; // the color of the visible overlay
84 OverviewColor overlay_outline_color; // the color of the outline of the overlay
85 gboolean overlay_inverted;// draw overlay over the visible area instead of around it
86 gboolean double_buffered; // whether to enable double-buffering on internal scintilla canvas
87 gint scroll_lines; // number of lines to scroll each scroll-event
88 gboolean show_scrollbar; // show the main scintilla's scrollbar
89 gboolean mouse_down; // whether the mouse is down
90 gulong update_rect; // signal id of idle rect handler
91 gulong conf_event; // signal id of the configure event on scintilla internal drawing area
92 GtkWidget *src_canvas; // internal drawing area of main scintilla
93 };
94
95 struct OverviewScintillaClass_
96 {
97 ScintillaClass parent_class;
98 };
99
100 static GParamSpec *pspecs[N_PROPERTIES] = { NULL };
101
102 static void overview_scintilla_finalize (GObject *object);
103 static void overview_scintilla_set_property (GObject *object,
104 guint prop_id,
105 const GValue *value,
106 GParamSpec *pspec);
107 static void overview_scintilla_get_property (GObject *object,
108 guint prop_id,
109 GValue *value,
110 GParamSpec *pspec);
111 static void overview_scintilla_set_src_sci (OverviewScintilla *self,
112 ScintillaObject *sci);
113
114 #if GTK_CHECK_VERSION (3, 0, 0)
115 static gboolean overview_scintilla_draw (GtkWidget *widget, cairo_t *cr, gpointer user_data);
116 #else
117 static gboolean overview_scintilla_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data);
118 #endif
119
G_DEFINE_TYPE(OverviewScintilla,overview_scintilla,scintilla_get_type ())120 G_DEFINE_TYPE (OverviewScintilla, overview_scintilla, scintilla_get_type())
121
122 static void
123 overview_scintilla_class_init (OverviewScintillaClass *klass)
124 {
125 GObjectClass *g_object_class;
126
127 g_object_class = G_OBJECT_CLASS (klass);
128
129 g_object_class->finalize = overview_scintilla_finalize;
130 g_object_class->set_property = overview_scintilla_set_property;
131 g_object_class->get_property = overview_scintilla_get_property;
132
133 pspecs[PROP_SCINTILLA] =
134 g_param_spec_object ("scintilla",
135 "Scintilla",
136 "The source ScintillaObject",
137 scintilla_get_type (),
138 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
139
140 pspecs[PROP_CURSOR] =
141 g_param_spec_enum ("cursor",
142 "Cursor",
143 "The GdkCursorType to use for the mouse cursor",
144 GDK_TYPE_CURSOR_TYPE,
145 OVERVIEW_SCINTILLA_CURSOR,
146 G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
147
148 pspecs[PROP_VISIBLE_RECT] =
149 g_param_spec_boxed ("visible-rect",
150 "VisibleRect",
151 "The visible area indication rectangle to draw",
152 GDK_TYPE_RECTANGLE,
153 G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
154
155 pspecs[PROP_WIDTH] =
156 g_param_spec_uint ("width",
157 "Width",
158 "Width of the overview",
159 OVERVIEW_SCINTILLA_WIDTH_MIN,
160 OVERVIEW_SCINTILLA_WIDTH_MAX,
161 OVERVIEW_SCINTILLA_WIDTH_DEF,
162 G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
163
164 pspecs[PROP_ZOOM] =
165 g_param_spec_int ("zoom",
166 "Zoom",
167 "The zoom-level of the overview",
168 OVERVIEW_SCINTILLA_ZOOM_MIN,
169 OVERVIEW_SCINTILLA_ZOOM_MAX,
170 OVERVIEW_SCINTILLA_ZOOM_DEF,
171 G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
172
173 pspecs[PROP_SHOW_TOOLTIP] =
174 g_param_spec_boolean ("show-tooltip",
175 "ShowTooltip",
176 "Whether to show a tooltip with addition info on mouse over",
177 TRUE,
178 G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
179
180 pspecs[PROP_OVERLAY_ENABLED] =
181 g_param_spec_boolean ("overlay-enabled",
182 "OverlayEnabled",
183 "Whether an overlay is drawn ontop of the overview",
184 TRUE,
185 G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
186
187 pspecs[PROP_OVERLAY_COLOR] =
188 g_param_spec_boxed ("overlay-color",
189 "OverlayColor",
190 "The color of the overlay, if enabled",
191 OVERVIEW_TYPE_COLOR,
192 G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
193
194 pspecs[PROP_OVERLAY_OUTLINE_COLOR] =
195 g_param_spec_boxed ("overlay-outline-color",
196 "OverlayOutlineColor",
197 "The color of the overlay's outline, if enabled",
198 OVERVIEW_TYPE_COLOR,
199 G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
200
201 pspecs[PROP_OVERLAY_INVERTED] =
202 g_param_spec_boolean ("overlay-inverted",
203 "OverlayInverted",
204 "Whether to draw the overlay over the visible area",
205 TRUE,
206 G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
207
208 pspecs[PROP_DOUBLE_BUFFERED] =
209 g_param_spec_boolean ("double-buffered",
210 "DoubleBuffered",
211 "Whether the overview Scintilla's internal canvas is double-buffered",
212 TRUE,
213 G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
214
215 pspecs[PROP_SCROLL_LINES] =
216 g_param_spec_int ("scroll-lines",
217 "ScrollLines",
218 "The number of lines to move each scroll, -1 for default, 0 to disable.",
219 -1, 100, OVERVIEW_SCINTILLA_SCROLL_LINES,
220 G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
221
222 pspecs[PROP_SHOW_SCROLLBAR] =
223 g_param_spec_boolean ("show-scrollbar",
224 "ShowScrollbar",
225 "Whether to show the scrollbar in the main Scintilla",
226 TRUE,
227 G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
228
229 g_object_class_install_properties (g_object_class, N_PROPERTIES, pspecs);
230 }
231
232 static void
overview_scintilla_finalize(GObject * object)233 overview_scintilla_finalize (GObject *object)
234 {
235 OverviewScintilla *self;
236
237 g_return_if_fail (OVERVIEW_IS_SCINTILLA (object));
238
239 self = OVERVIEW_SCINTILLA (object);
240
241 if (GTK_IS_WIDGET (self->src_canvas) && self->conf_event != 0)
242 g_signal_handler_disconnect (self->src_canvas, self->conf_event);
243
244 g_object_unref (self->sci);
245
246 G_OBJECT_CLASS (overview_scintilla_parent_class)->finalize (object);
247 }
248
249 static inline void
cairo_set_source_overlay_color_(cairo_t * cr,const OverviewColor * color)250 cairo_set_source_overlay_color_ (cairo_t *cr,
251 const OverviewColor *color)
252 {
253 cairo_set_source_rgba (cr, color->red, color->green, color->blue, color->alpha);
254 }
255
256 static inline void
overview_scintilla_draw_real(OverviewScintilla * self,cairo_t * cr)257 overview_scintilla_draw_real (OverviewScintilla *self,
258 cairo_t *cr)
259 {
260 if (! self->overlay_enabled)
261 return;
262
263 GtkAllocation alloc;
264
265 gtk_widget_get_allocation (GTK_WIDGET (self->canvas), &alloc);
266
267 cairo_save (cr);
268
269 cairo_set_line_width (cr, 1.0);
270
271 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0)
272 cairo_set_antialias (cr, CAIRO_ANTIALIAS_GOOD);
273 #endif
274
275 if (self->overlay_inverted)
276 {
277 cairo_set_source_overlay_color_ (cr, &self->overlay_color);
278 cairo_rectangle (cr,
279 0,
280 self->visible_rect.y,
281 alloc.width,
282 self->visible_rect.height);
283 cairo_fill (cr);
284 }
285 else
286 {
287 // draw a rectangle at the top and bottom to obscure the non-visible area
288 cairo_set_source_overlay_color_ (cr, &self->overlay_color);
289 cairo_rectangle (cr, 0, 0, alloc.width, self->visible_rect.y);
290 cairo_rectangle (cr,
291 0,
292 self->visible_rect.y + self->visible_rect.height,
293 alloc.width,
294 alloc.height - (self->visible_rect.y + self->visible_rect.height));
295 cairo_fill (cr);
296 }
297
298 // draw a highlighting border at top and bottom of visible rect
299 cairo_set_source_overlay_color_ (cr, &self->overlay_outline_color);
300 cairo_move_to (cr, self->visible_rect.x + 0.5, self->visible_rect.y + 0.5);
301 cairo_line_to (cr, self->visible_rect.width, self->visible_rect.y + 0.5);
302 cairo_move_to (cr, self->visible_rect.x + 0.5, self->visible_rect.y + 0.5 + self->visible_rect.height);
303 cairo_line_to (cr, self->visible_rect.width, self->visible_rect.y + 0.5 + self->visible_rect.height);
304 cairo_stroke (cr);
305
306 // draw a left border if there's no scrollbar
307 if (! overview_scintilla_get_show_scrollbar (self))
308 {
309 cairo_move_to (cr, 0.5, 0.5);
310 cairo_line_to (cr, 0.5, alloc.height);
311 cairo_stroke (cr);
312 }
313
314 cairo_restore (cr);
315 }
316
317 #if GTK_CHECK_VERSION (3, 0, 0)
318 static gboolean
overview_scintilla_draw(GtkWidget * widget,cairo_t * cr,gpointer user_data)319 overview_scintilla_draw (GtkWidget *widget,
320 cairo_t *cr,
321 gpointer user_data)
322 {
323 overview_scintilla_draw_real (OVERVIEW_SCINTILLA (user_data), cr);
324 return FALSE;
325 }
326 #else
327 static gboolean
overview_scintilla_expose_event(GtkWidget * widget,GdkEventExpose * event,gpointer user_data)328 overview_scintilla_expose_event (GtkWidget *widget,
329 GdkEventExpose *event,
330 gpointer user_data)
331 {
332 cairo_t *cr;
333 cr = gdk_cairo_create (gtk_widget_get_window (widget));
334 overview_scintilla_draw_real (OVERVIEW_SCINTILLA (user_data), cr);
335 cairo_destroy (cr);
336 return FALSE;
337 }
338 #endif
339
340 static gboolean
on_focus_in_event(OverviewScintilla * self,GdkEventFocus * event,ScintillaObject * sci)341 on_focus_in_event (OverviewScintilla *self,
342 GdkEventFocus *event,
343 ScintillaObject *sci)
344 {
345 sci_send (self, SETREADONLY, 1, 0);
346 return TRUE;
347 }
348
349 static gboolean
on_focus_out_event(OverviewScintilla * self,GdkEventFocus * event,ScintillaObject * sci)350 on_focus_out_event (OverviewScintilla *self,
351 GdkEventFocus *event,
352 ScintillaObject *sci)
353 {
354 GeanyDocument *doc = g_object_get_data (G_OBJECT (sci), "document");
355 if (DOC_VALID (doc))
356 sci_send (self, SETREADONLY, doc->readonly, 0);
357 else
358 sci_send (self, SETREADONLY, 0, 0);
359 return TRUE;
360 }
361
362 static gboolean
on_enter_notify_event(OverviewScintilla * self,GdkEventCrossing * event,ScintillaObject * sci)363 on_enter_notify_event (OverviewScintilla *self,
364 GdkEventCrossing *event,
365 ScintillaObject *sci)
366 {
367 return TRUE;
368 }
369
370 static gboolean
on_leave_notify_event(OverviewScintilla * self,GdkEventCrossing * event,ScintillaObject * sci)371 on_leave_notify_event (OverviewScintilla *self,
372 GdkEventCrossing *event,
373 ScintillaObject *sci)
374 {
375 return TRUE;
376 }
377
378 static void
on_each_child(GtkWidget * child,GList ** list)379 on_each_child (GtkWidget *child,
380 GList **list)
381 {
382 *list = g_list_prepend (*list, child);
383 }
384
385 static GList *
gtk_container_get_internal_children_(GtkContainer * cont)386 gtk_container_get_internal_children_ (GtkContainer *cont)
387 {
388 GList *list = NULL;
389 gtk_container_forall (cont, (GtkCallback) on_each_child, &list);
390 return g_list_reverse (list);
391 }
392
393 static GtkWidget *
overview_scintilla_find_drawing_area(GtkWidget * root)394 overview_scintilla_find_drawing_area (GtkWidget *root)
395 {
396 GtkWidget *da = NULL;
397 if (GTK_IS_DRAWING_AREA (root))
398 da = root;
399 else if (GTK_IS_CONTAINER (root))
400 {
401 GList *children = gtk_container_get_internal_children_ (GTK_CONTAINER (root));
402 for (GList *iter = children; iter != NULL; iter = g_list_next (iter))
403 {
404 GtkWidget *wid = overview_scintilla_find_drawing_area (iter->data);
405 if (GTK_IS_DRAWING_AREA (wid))
406 {
407 da = wid;
408 break;
409 }
410 }
411 g_list_free (children);
412 }
413 return da;
414 }
415
416 static gboolean
on_scroll_event(OverviewScintilla * self,GdkEventScroll * event,GtkWidget * widget)417 on_scroll_event (OverviewScintilla *self,
418 GdkEventScroll *event,
419 GtkWidget *widget)
420 {
421 gint delta = 0;
422
423 if (self->scroll_lines == 0)
424 return TRUE;
425
426 if (event->direction == GDK_SCROLL_UP)
427 delta = -(self->scroll_lines);
428 else if (event->direction == GDK_SCROLL_DOWN)
429 delta = self->scroll_lines;
430
431 if (delta != 0)
432 sci_send (self->sci, LINESCROLL, 0, delta);
433
434 return TRUE;
435 }
436
437 static void
overview_scintilla_goto_point(OverviewScintilla * self,gint x,gint y)438 overview_scintilla_goto_point (OverviewScintilla *self,
439 gint x,
440 gint y)
441 {
442 gint pos;
443 pos = sci_send (self, POSITIONFROMPOINT, x, y);
444 if (pos >= 0)
445 sci_send (self->sci, GOTOPOS, pos, 0);
446 }
447
448 static void
overview_scintilla_update_cursor(OverviewScintilla * self)449 overview_scintilla_update_cursor (OverviewScintilla *self)
450 {
451 if (GTK_IS_WIDGET (self->canvas) && gtk_widget_get_mapped (self->canvas))
452 {
453 GdkCursor *cursor = gdk_cursor_new (self->active_cursor);
454 gdk_window_set_cursor (gtk_widget_get_window (self->canvas), cursor);
455 gdk_cursor_unref (cursor);
456 }
457 }
458
459 static gboolean
on_button_press_event(OverviewScintilla * self,GdkEventButton * event,GtkWidget * widget)460 on_button_press_event (OverviewScintilla *self,
461 GdkEventButton *event,
462 GtkWidget *widget)
463 {
464 self->mouse_down = TRUE;
465 self->active_cursor = OVERVIEW_SCINTILLA_CURSOR_CLICK;
466 overview_scintilla_update_cursor (self);
467 return TRUE;
468 }
469
470 static gboolean
on_button_release_event(OverviewScintilla * self,GdkEventButton * event,GtkWidget * widget)471 on_button_release_event (OverviewScintilla *self,
472 GdkEventButton *event,
473 GtkWidget *widget)
474 {
475 self->mouse_down = FALSE;
476 self->active_cursor = OVERVIEW_SCINTILLA_CURSOR;
477 overview_scintilla_update_cursor (self);
478 overview_scintilla_goto_point (self, event->x, event->y);
479 return TRUE;
480 }
481
482 static gboolean
on_motion_notify_event(OverviewScintilla * self,GdkEventMotion * event,GtkWidget * widget)483 on_motion_notify_event (OverviewScintilla *self,
484 GdkEventMotion *event,
485 GtkWidget *widget)
486 {
487 if (self->mouse_down)
488 {
489 if (self->active_cursor != OVERVIEW_SCINTILLA_CURSOR_SCROLL)
490 {
491 self->active_cursor = OVERVIEW_SCINTILLA_CURSOR_SCROLL;
492 overview_scintilla_update_cursor (self);
493 }
494 overview_scintilla_goto_point (self, event->x, event->y);
495 }
496 return TRUE;
497 }
498
499 static gboolean
overview_scintilla_setup_tooltip(OverviewScintilla * self,gint x,gint y,GtkTooltip * tooltip)500 overview_scintilla_setup_tooltip (OverviewScintilla *self,
501 gint x,
502 gint y,
503 GtkTooltip *tooltip)
504 {
505 gint pos;
506
507 if (!self->show_tooltip)
508 return FALSE;
509
510 pos = sci_send (self, POSITIONFROMPOINT, x, y);
511 if (pos >= 0)
512 {
513 gint line = sci_send (self, LINEFROMPOSITION, pos, 0);
514 gint column = sci_send (self, GETCOLUMN, pos, 0);
515 gchar *text =
516 g_strdup_printf (_("Line <b>%d</b>, Column <b>%d</b>, Position <b>%d</b>"),
517 line, column, pos);
518 gtk_tooltip_set_markup (tooltip, text);
519 g_free (text);
520 }
521 else
522 gtk_tooltip_set_text (tooltip, NULL);
523
524 return TRUE;
525 }
526
527 static gboolean
on_query_tooltip(OverviewScintilla * self,gint x,gint y,gboolean kbd_mode,GtkTooltip * tooltip,GtkWidget * widget)528 on_query_tooltip (OverviewScintilla *self,
529 gint x,
530 gint y,
531 gboolean kbd_mode,
532 GtkTooltip *tooltip,
533 GtkWidget *widget)
534 {
535 if (!kbd_mode)
536 return overview_scintilla_setup_tooltip (self, x, y, tooltip);
537 return FALSE;
538 }
539
540 static void
overview_scintilla_setup_canvas(OverviewScintilla * self)541 overview_scintilla_setup_canvas (OverviewScintilla *self)
542 {
543 if (!GTK_IS_WIDGET (self->canvas))
544 {
545 self->canvas = overview_scintilla_find_drawing_area (GTK_WIDGET (self));
546
547 gtk_widget_add_events (self->canvas,
548 GDK_EXPOSURE_MASK |
549 GDK_BUTTON_PRESS_MASK |
550 GDK_BUTTON_RELEASE_MASK |
551 GDK_POINTER_MOTION_MASK |
552 GDK_SCROLL_MASK);
553
554 g_signal_connect_swapped (self->canvas,
555 "scroll-event",
556 G_CALLBACK (on_scroll_event),
557 self);
558 g_signal_connect_swapped (self->canvas,
559 "button-press-event",
560 G_CALLBACK (on_button_press_event),
561 self);
562 g_signal_connect_swapped (self->canvas,
563 "button-release-event",
564 G_CALLBACK (on_button_release_event),
565 self);
566 g_signal_connect_swapped (self->canvas,
567 "motion-notify-event",
568 G_CALLBACK (on_motion_notify_event),
569 self);
570 g_signal_connect_swapped (self->canvas,
571 "query-tooltip",
572 G_CALLBACK (on_query_tooltip),
573 self);
574
575 gtk_widget_set_has_tooltip (self->canvas, self->show_tooltip);
576
577 #if GTK_CHECK_VERSION (3, 0, 0)
578 g_signal_connect_after (self->canvas,
579 "draw",
580 G_CALLBACK (overview_scintilla_draw),
581 self);
582 #else
583 g_signal_connect_after (self->canvas,
584 "expose-event",
585 G_CALLBACK (overview_scintilla_expose_event),
586 self);
587 #endif
588
589 }
590 }
591
592 static void
overview_scintilla_update_rect(OverviewScintilla * self)593 overview_scintilla_update_rect (OverviewScintilla *self)
594 {
595 GtkAllocation alloc;
596 GdkRectangle rect;
597 gint first_line, n_lines, last_line;
598 gint pos_start, pos_end;
599 gint ystart, yend;
600
601 gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
602
603 first_line = sci_send (self->sci, GETFIRSTVISIBLELINE, 0, 0);
604 n_lines = sci_send (self->sci, LINESONSCREEN, 0, 0);
605 last_line = first_line + n_lines;
606
607 pos_start = sci_send (self, POSITIONFROMLINE, first_line, 0);
608 pos_end = sci_send (self, POSITIONFROMLINE, last_line, 0);
609
610 ystart = sci_send (self, POINTYFROMPOSITION, 0, pos_start);
611 yend = sci_send (self, POINTYFROMPOSITION, 0, pos_end);
612
613 if (yend >= alloc.height || yend == 0)
614 {
615 n_lines = sci_send (self, GETLINECOUNT, 0, 0);
616 last_line = n_lines - 1;
617 pos_end = sci_send (self, POSITIONFROMLINE, last_line, 0);
618 yend = sci_send (self, POINTYFROMPOSITION, 0, pos_end);
619 }
620
621 rect.x = 0;
622 rect.width = alloc.width - 1;
623 rect.y = ystart;
624 rect.height = yend - ystart;
625
626 overview_scintilla_set_visible_rect (self, &rect);
627 }
628
629 static gint
sci_get_midline_(gpointer sci)630 sci_get_midline_ (gpointer sci)
631 {
632 gint first, count;
633 first = sci_send (sci, GETFIRSTVISIBLELINE, 0, 0);
634 count = sci_send (sci, LINESONSCREEN, 0, 0);
635 return first + (count / 2);
636 }
637
638 static void
overview_scintilla_sync_center(OverviewScintilla * self)639 overview_scintilla_sync_center (OverviewScintilla *self)
640 {
641 gint mid_src = sci_get_midline_ (self->sci);
642 gint mid_dst = sci_get_midline_ (self);
643 gint delta = mid_src - mid_dst;
644 sci_send (self, LINESCROLL, 0, delta);
645 overview_scintilla_update_rect (self);
646 }
647
648 static gboolean
on_map_event(OverviewScintilla * self,GdkEventAny * event,ScintillaObject * sci)649 on_map_event (OverviewScintilla *self,
650 GdkEventAny *event,
651 ScintillaObject *sci)
652 {
653 overview_scintilla_setup_canvas (self);
654
655 if (GTK_IS_WIDGET (self->canvas) &&
656 gtk_widget_get_double_buffered (self->canvas) != self->double_buffered)
657 {
658 gtk_widget_set_double_buffered (self->canvas, self->double_buffered);
659 self->double_buffered = gtk_widget_get_double_buffered (self->canvas);
660 }
661
662 overview_scintilla_update_cursor (self);
663 overview_scintilla_update_rect (self);
664
665 return FALSE;
666 }
667
668 #define self_connect(name, cb) \
669 g_signal_connect_swapped (self, name, G_CALLBACK (cb), self)
670
671 static void
overview_scintilla_init(OverviewScintilla * self)672 overview_scintilla_init (OverviewScintilla *self)
673 {
674 self->sci = NULL;
675 self->canvas = NULL;
676 self->cursor = OVERVIEW_SCINTILLA_CURSOR;
677 self->active_cursor = OVERVIEW_SCINTILLA_CURSOR;
678 self->update_rect = 0;
679 self->conf_event = 0;
680 self->src_canvas = NULL;
681 self->width = OVERVIEW_SCINTILLA_WIDTH_DEF;
682 self->zoom = OVERVIEW_SCINTILLA_ZOOM_DEF;
683 self->mouse_down = FALSE;
684 self->show_tooltip = TRUE;
685 self->double_buffered = TRUE;
686 self->scroll_lines = OVERVIEW_SCINTILLA_SCROLL_LINES;
687 self->show_scrollbar = TRUE;
688 self->overlay_inverted = TRUE;
689
690 memset (&self->visible_rect, 0, sizeof (GdkRectangle));
691 memcpy (&self->overlay_color, &def_overlay_color, sizeof (OverviewColor));
692 memcpy (&self->overlay_outline_color, &def_overlay_outline_color, sizeof (OverviewColor));
693
694 gtk_widget_add_events (GTK_WIDGET (self),
695 GDK_EXPOSURE_MASK |
696 GDK_FOCUS_CHANGE_MASK |
697 GDK_ENTER_NOTIFY_MASK |
698 GDK_STRUCTURE_MASK);
699
700 self_connect ("focus-in-event", on_focus_in_event);
701 self_connect ("focus-out-event", on_focus_out_event);
702 self_connect ("enter-notify-event", on_enter_notify_event);
703 self_connect ("leave-notify-event", on_leave_notify_event);
704 self_connect ("map-event", on_map_event);
705 }
706
707 static void
overview_scintilla_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)708 overview_scintilla_set_property (GObject *object,
709 guint prop_id,
710 const GValue *value,
711 GParamSpec *pspec)
712 {
713 OverviewScintilla *self = OVERVIEW_SCINTILLA (object);
714
715 switch (prop_id)
716 {
717 case PROP_SCINTILLA:
718 overview_scintilla_set_src_sci (self, g_value_get_object (value));
719 break;
720 case PROP_CURSOR:
721 overview_scintilla_set_cursor (self, g_value_get_enum (value));
722 break;
723 case PROP_VISIBLE_RECT:
724 overview_scintilla_set_visible_rect (self, g_value_get_boxed (value));
725 break;
726 case PROP_WIDTH:
727 overview_scintilla_set_width (self, g_value_get_uint (value));
728 break;
729 case PROP_ZOOM:
730 overview_scintilla_set_zoom (self, g_value_get_int (value));
731 break;
732 case PROP_SHOW_TOOLTIP:
733 overview_scintilla_set_show_tooltip (self, g_value_get_boolean (value));
734 break;
735 case PROP_OVERLAY_ENABLED:
736 overview_scintilla_set_overlay_enabled (self, g_value_get_boolean (value));
737 break;
738 case PROP_OVERLAY_COLOR:
739 overview_scintilla_set_overlay_color (self, g_value_get_boxed (value));
740 break;
741 case PROP_OVERLAY_OUTLINE_COLOR:
742 overview_scintilla_set_overlay_outline_color (self, g_value_get_boxed (value));
743 break;
744 case PROP_OVERLAY_INVERTED:
745 overview_scintilla_set_overlay_inverted (self, g_value_get_boolean (value));
746 break;
747 case PROP_DOUBLE_BUFFERED:
748 overview_scintilla_set_double_buffered (self, g_value_get_boolean (value));
749 break;
750 case PROP_SCROLL_LINES:
751 overview_scintilla_set_scroll_lines (self, g_value_get_int (value));
752 break;
753 case PROP_SHOW_SCROLLBAR:
754 overview_scintilla_set_show_scrollbar (self, g_value_get_boolean (value));
755 break;
756 default:
757 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
758 break;
759 }
760 }
761
762 static void
overview_scintilla_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)763 overview_scintilla_get_property (GObject *object,
764 guint prop_id,
765 GValue *value,
766 GParamSpec *pspec)
767 {
768 OverviewScintilla *self = OVERVIEW_SCINTILLA (object);
769
770 switch (prop_id)
771 {
772 case PROP_SCINTILLA:
773 g_value_set_object (value, self->sci);
774 break;
775 case PROP_CURSOR:
776 g_value_set_enum (value, overview_scintilla_get_cursor (self));
777 break;
778 case PROP_VISIBLE_RECT:
779 {
780 GdkRectangle rect;
781 overview_scintilla_get_visible_rect (self, &rect);
782 g_value_set_boxed (value, &rect);
783 break;
784 }
785 case PROP_WIDTH:
786 g_value_set_uint (value, overview_scintilla_get_width (self));
787 break;
788 case PROP_ZOOM:
789 g_value_set_int (value, overview_scintilla_get_zoom (self));
790 break;
791 case PROP_SHOW_TOOLTIP:
792 g_value_set_boolean (value, overview_scintilla_get_show_tooltip (self));
793 break;
794 case PROP_OVERLAY_ENABLED:
795 g_value_set_boolean (value, overview_scintilla_get_overlay_enabled (self));
796 break;
797 case PROP_OVERLAY_COLOR:
798 {
799 OverviewColor color = { 0 };
800 overview_scintilla_get_overlay_color (self, &color);
801 g_value_set_boxed (value, &color);
802 break;
803 }
804 case PROP_OVERLAY_OUTLINE_COLOR:
805 {
806 OverviewColor color = { 0 };
807 overview_scintilla_get_overlay_outline_color (self, &color);
808 g_value_set_boxed (value, &color);
809 break;
810 }
811 case PROP_OVERLAY_INVERTED:
812 g_value_set_boolean (value, overview_scintilla_get_overlay_inverted (self));
813 break;
814 case PROP_DOUBLE_BUFFERED:
815 g_value_set_boolean (value, overview_scintilla_get_double_buffered (self));
816 break;
817 case PROP_SCROLL_LINES:
818 g_value_set_int (value, overview_scintilla_get_scroll_lines (self));
819 break;
820 case PROP_SHOW_SCROLLBAR:
821 g_value_set_boolean (value, overview_scintilla_get_show_scrollbar (self));
822 break;
823 default:
824 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
825 break;
826 }
827 }
828
829 GtkWidget *
overview_scintilla_new(ScintillaObject * src_sci)830 overview_scintilla_new (ScintillaObject *src_sci)
831 {
832 return g_object_new (OVERVIEW_TYPE_SCINTILLA, "scintilla", src_sci, NULL);
833 }
834
835 static gchar *
sci_get_font(ScintillaObject * sci,gint style)836 sci_get_font (ScintillaObject *sci,
837 gint style)
838 {
839 gsize len = sci_send (sci, STYLEGETFONT, style, 0);
840 gchar *name = g_malloc0 (len + 1);
841 sci_send (sci, STYLEGETFONT, style, name);
842 return name;
843 }
844
845 static gboolean
on_src_sci_configure_event(GtkWidget * widget,GdkEventConfigure * event,OverviewScintilla * self)846 on_src_sci_configure_event (GtkWidget *widget,
847 GdkEventConfigure *event,
848 OverviewScintilla *self)
849 {
850 overview_scintilla_sync_center (self);
851 return FALSE;
852 }
853
854 static gboolean
on_src_sci_map_event(ScintillaObject * sci,GdkEvent * event,OverviewScintilla * self)855 on_src_sci_map_event (ScintillaObject *sci,
856 GdkEvent *event,
857 OverviewScintilla *self)
858 {
859 if (self->conf_event == 0)
860 {
861 GtkWidget *internal;
862 internal = overview_scintilla_find_drawing_area (GTK_WIDGET (sci));
863 if (GTK_IS_DRAWING_AREA (internal))
864 {
865 self->src_canvas = internal;
866 self->conf_event = g_signal_connect (self->src_canvas,
867 "configure-event",
868 G_CALLBACK (on_src_sci_configure_event),
869 self);
870 }
871 }
872 return FALSE;
873 }
874
875 static void
on_src_sci_notify(ScintillaObject * sci,gpointer unused,SCNotification * nt,OverviewScintilla * self)876 on_src_sci_notify (ScintillaObject *sci,
877 gpointer unused,
878 SCNotification *nt,
879 OverviewScintilla *self)
880 {
881 if (nt->nmhdr.code == SCN_UPDATEUI && nt->updated & SC_UPDATE_V_SCROLL)
882 {
883 overview_scintilla_sync_center (self);
884 if (GTK_IS_WIDGET (self->canvas))
885 gtk_widget_queue_draw (self->canvas);
886 }
887 }
888
889 static void
overview_scintilla_clone_styles(OverviewScintilla * self)890 overview_scintilla_clone_styles (OverviewScintilla *self)
891 {
892 ScintillaObject *sci = SCINTILLA (self);
893 ScintillaObject *src_sci = self->sci;
894
895 for (gint i = 0; i < STYLE_MAX; i++)
896 {
897 gchar *font_name = sci_get_font (src_sci, i);
898 gint font_size = sci_send (src_sci, STYLEGETSIZE, i, 0);
899 gint weight = sci_send (src_sci, STYLEGETWEIGHT, i, 0);
900 gboolean italic = sci_send (src_sci, STYLEGETITALIC, i, 0);
901 gint fg_color = sci_send (src_sci, STYLEGETFORE, i, 0);
902 gint bg_color = sci_send (src_sci, STYLEGETBACK, i, 0);
903
904 sci_send (sci, STYLESETFONT, i, font_name);
905 sci_send (sci, STYLESETSIZE, i, font_size);
906 sci_send (sci, STYLESETWEIGHT, i, weight);
907 sci_send (sci, STYLESETITALIC, i, italic);
908 sci_send (sci, STYLESETFORE, i, fg_color);
909 sci_send (sci, STYLESETBACK, i, bg_color);
910 sci_send (sci, STYLESETCHANGEABLE, i, 0);
911
912 g_free (font_name);
913 }
914 }
915
916 static void
overview_scintilla_queue_draw(OverviewScintilla * self)917 overview_scintilla_queue_draw (OverviewScintilla *self)
918 {
919 if (GTK_IS_WIDGET (self->canvas))
920 gtk_widget_queue_draw (self->canvas);
921 else
922 gtk_widget_queue_draw (GTK_WIDGET (self));
923 }
924
925 void
overview_scintilla_sync(OverviewScintilla * self)926 overview_scintilla_sync (OverviewScintilla *self)
927 {
928 sptr_t doc_ptr;
929
930 g_return_if_fail (OVERVIEW_IS_SCINTILLA (self));
931
932 doc_ptr = sci_send (self->sci, GETDOCPOINTER, 0, 0);
933 sci_send (self, SETDOCPOINTER, 0, doc_ptr);
934
935 overview_scintilla_clone_styles (self);
936
937 for (gint i = 0; i < SC_MAX_MARGIN; i++)
938 sci_send (self, SETMARGINWIDTHN, i, 0);
939
940 sci_send (self, SETVIEWEOL, 0, 0);
941 sci_send (self, SETVIEWWS, 0, 0);
942 sci_send (self, SETHSCROLLBAR, 0, 0);
943 sci_send (self, SETVSCROLLBAR, 0, 0);
944 sci_send (self, SETZOOM, self->zoom, 0);
945 sci_send (self, SETCURSOR, SC_CURSORARROW, 0);
946 sci_send (self, SETENDATLASTLINE, sci_send (self->sci, GETENDATLASTLINE, 0, 0), 0);
947 sci_send (self, SETMOUSEDOWNCAPTURES, 0, 0);
948 sci_send (self, SETCARETPERIOD, 0, 0);
949 sci_send (self, SETCARETWIDTH, 0, 0);
950 sci_send (self, SETEXTRAASCENT, 0, 0);
951 sci_send (self, SETEXTRADESCENT, 0, 0);
952
953 sci_send (self->sci, SETVSCROLLBAR, self->show_scrollbar, 0);
954
955 overview_scintilla_update_cursor (self);
956 overview_scintilla_update_rect (self);
957 overview_scintilla_sync_center (self);
958
959 overview_scintilla_queue_draw (self);
960 }
961
962 static void
overview_scintilla_set_src_sci(OverviewScintilla * self,ScintillaObject * sci)963 overview_scintilla_set_src_sci (OverviewScintilla *self,
964 ScintillaObject *sci)
965 {
966
967 g_assert (! IS_SCINTILLA (self->sci));
968
969 self->sci = g_object_ref (sci);
970
971 overview_scintilla_sync (self);
972 sci_send (self->sci, SETVSCROLLBAR, self->show_scrollbar, 0);
973
974 gtk_widget_add_events (GTK_WIDGET (self->sci), GDK_STRUCTURE_MASK);
975 plugin_signal_connect (geany_plugin,
976 G_OBJECT (self->sci),
977 "map-event",
978 TRUE,
979 G_CALLBACK (on_src_sci_map_event),
980 self);
981
982 plugin_signal_connect (geany_plugin,
983 G_OBJECT (self->sci),
984 "sci-notify",
985 TRUE,
986 G_CALLBACK (on_src_sci_notify),
987 self);
988
989 g_object_notify (G_OBJECT (self), "scintilla");
990 }
991
992 GdkCursorType
overview_scintilla_get_cursor(OverviewScintilla * self)993 overview_scintilla_get_cursor (OverviewScintilla *self)
994 {
995 g_return_val_if_fail (OVERVIEW_IS_SCINTILLA (self), GDK_ARROW);
996 return self->cursor;
997 }
998
999 void
overview_scintilla_set_cursor(OverviewScintilla * self,GdkCursorType cursor_type)1000 overview_scintilla_set_cursor (OverviewScintilla *self,
1001 GdkCursorType cursor_type)
1002 {
1003 g_return_if_fail (OVERVIEW_IS_SCINTILLA (self));
1004 if (cursor_type != self->cursor)
1005 {
1006 self->cursor = cursor_type;
1007 self->active_cursor = cursor_type;
1008 overview_scintilla_update_cursor (self);
1009 g_object_notify (G_OBJECT (self), "cursor");
1010 }
1011 }
1012
1013 void
overview_scintilla_get_visible_rect(OverviewScintilla * self,GdkRectangle * rect)1014 overview_scintilla_get_visible_rect (OverviewScintilla *self,
1015 GdkRectangle *rect)
1016 {
1017 g_return_if_fail (OVERVIEW_IS_SCINTILLA (self));
1018 g_return_if_fail (rect != NULL);
1019
1020 memcpy (rect, &self->visible_rect, sizeof (GdkRectangle));
1021 }
1022
1023 void
overview_scintilla_set_visible_rect(OverviewScintilla * self,const GdkRectangle * rect)1024 overview_scintilla_set_visible_rect (OverviewScintilla *self,
1025 const GdkRectangle *rect)
1026 {
1027 g_return_if_fail (OVERVIEW_IS_SCINTILLA (self));
1028
1029 if (rect == NULL)
1030 {
1031 memset (&self->visible_rect, 0, sizeof (GdkRectangle));
1032 g_object_notify (G_OBJECT (self), "visible-rect");
1033 return;
1034 }
1035
1036 if (rect->x != self->visible_rect.x ||
1037 rect->y != self->visible_rect.y ||
1038 rect->width != self->visible_rect.width ||
1039 rect->height != self->visible_rect.height)
1040 {
1041 memcpy (&self->visible_rect, rect, sizeof (GdkRectangle));
1042 if (GTK_IS_WIDGET (self->canvas))
1043 gtk_widget_queue_draw (self->canvas);
1044 g_object_notify (G_OBJECT (self), "visible-rect");
1045 }
1046 }
1047
1048 guint
overview_scintilla_get_width(OverviewScintilla * self)1049 overview_scintilla_get_width (OverviewScintilla *self)
1050 {
1051 GtkAllocation alloc;
1052 g_return_val_if_fail (OVERVIEW_IS_SCINTILLA (self), 0);
1053 gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
1054 return alloc.width;
1055 }
1056
1057 void
overview_scintilla_set_width(OverviewScintilla * self,guint width)1058 overview_scintilla_set_width (OverviewScintilla *self,
1059 guint width)
1060 {
1061 g_return_if_fail (OVERVIEW_IS_SCINTILLA (self));
1062 gtk_widget_set_size_request (GTK_WIDGET (self), width, -1);
1063 }
1064
1065 gint
overview_scintilla_get_zoom(OverviewScintilla * self)1066 overview_scintilla_get_zoom (OverviewScintilla *self)
1067 {
1068 g_return_val_if_fail (OVERVIEW_IS_SCINTILLA (self), 0);
1069 self->zoom = sci_send (self, GETZOOM, 0, 0);
1070 return self->zoom;
1071 }
1072
1073 void
overview_scintilla_set_zoom(OverviewScintilla * self,gint zoom)1074 overview_scintilla_set_zoom (OverviewScintilla *self,
1075 gint zoom)
1076 {
1077 gint old_zoom;
1078
1079 g_return_if_fail (OVERVIEW_IS_SCINTILLA (self));
1080 g_return_if_fail (zoom >= OVERVIEW_SCINTILLA_ZOOM_MIN &&
1081 zoom <= OVERVIEW_SCINTILLA_ZOOM_MAX);
1082
1083 old_zoom = sci_send (self, GETZOOM, 0, 0);
1084 if (zoom != old_zoom)
1085 {
1086 sci_send (self, SETZOOM, zoom, 0);
1087 self->zoom = sci_send (self, GETZOOM, 0, 0);
1088 if (self->zoom != old_zoom)
1089 {
1090 overview_scintilla_sync_center (self);
1091 g_object_notify (G_OBJECT (self), "zoom");
1092 }
1093 }
1094 }
1095
1096 gboolean
overview_scintilla_get_show_tooltip(OverviewScintilla * self)1097 overview_scintilla_get_show_tooltip (OverviewScintilla *self)
1098 {
1099 g_return_val_if_fail (OVERVIEW_IS_SCINTILLA (self), FALSE);
1100 return self->show_tooltip;
1101 }
1102
1103 void
overview_scintilla_set_show_tooltip(OverviewScintilla * self,gboolean show)1104 overview_scintilla_set_show_tooltip (OverviewScintilla *self,
1105 gboolean show)
1106 {
1107 g_return_if_fail (OVERVIEW_IS_SCINTILLA (self));
1108
1109 if (show != self->show_tooltip)
1110 {
1111 self->show_tooltip = show;
1112 if (GTK_IS_WIDGET (self->canvas))
1113 gtk_widget_set_has_tooltip (self->canvas, self->show_tooltip);
1114 g_object_notify (G_OBJECT (self), "show-tooltip");
1115 }
1116 }
1117
1118 gboolean
overview_scintilla_get_overlay_enabled(OverviewScintilla * self)1119 overview_scintilla_get_overlay_enabled (OverviewScintilla *self)
1120 {
1121 g_return_val_if_fail (OVERVIEW_IS_SCINTILLA (self), FALSE);
1122 return self->overlay_enabled;
1123 }
1124
1125 void
overview_scintilla_set_overlay_enabled(OverviewScintilla * self,gboolean enabled)1126 overview_scintilla_set_overlay_enabled (OverviewScintilla *self,
1127 gboolean enabled)
1128 {
1129 g_return_if_fail (OVERVIEW_IS_SCINTILLA (self));
1130
1131 if (enabled != self->overlay_enabled)
1132 {
1133 self->overlay_enabled = enabled;
1134 if (GTK_IS_WIDGET (self->canvas))
1135 gtk_widget_queue_draw (self->canvas);
1136 g_object_notify (G_OBJECT (self), "overlay-enabled");
1137 }
1138 }
1139
1140 void
overview_scintilla_get_overlay_color(OverviewScintilla * self,OverviewColor * color)1141 overview_scintilla_get_overlay_color (OverviewScintilla *self,
1142 OverviewColor *color)
1143 {
1144 g_return_if_fail (OVERVIEW_IS_SCINTILLA (self));
1145 g_return_if_fail (color != NULL);
1146 memcpy (color, &self->overlay_color, sizeof (OverviewColor));
1147 }
1148
1149 void
overview_scintilla_set_overlay_color(OverviewScintilla * self,const OverviewColor * color)1150 overview_scintilla_set_overlay_color (OverviewScintilla *self,
1151 const OverviewColor *color)
1152 {
1153 gboolean changed = FALSE;
1154 g_return_if_fail (OVERVIEW_IS_SCINTILLA (self));
1155
1156 if (color == NULL)
1157 {
1158 memcpy (&self->overlay_color, &def_overlay_color, sizeof (OverviewColor));
1159 changed = TRUE;
1160 }
1161 else if (!overview_color_equal (color, &self->overlay_color))
1162 {
1163 memcpy (&self->overlay_color, color, sizeof (OverviewColor));
1164 changed = TRUE;
1165 }
1166
1167 if (changed)
1168 {
1169 if (GTK_IS_WIDGET (self->canvas))
1170 gtk_widget_queue_draw (self->canvas);
1171 g_object_notify (G_OBJECT (self), "overlay-color");
1172 }
1173 }
1174
1175 void
overview_scintilla_get_overlay_outline_color(OverviewScintilla * self,OverviewColor * color)1176 overview_scintilla_get_overlay_outline_color (OverviewScintilla *self,
1177 OverviewColor *color)
1178 {
1179 g_return_if_fail (OVERVIEW_IS_SCINTILLA (self));
1180 g_return_if_fail (color != NULL);
1181 memcpy (color, &self->overlay_outline_color, sizeof (OverviewColor));
1182 }
1183
1184 void
overview_scintilla_set_overlay_outline_color(OverviewScintilla * self,const OverviewColor * color)1185 overview_scintilla_set_overlay_outline_color (OverviewScintilla *self,
1186 const OverviewColor *color)
1187 {
1188 gboolean changed = FALSE;
1189 g_return_if_fail (OVERVIEW_IS_SCINTILLA (self));
1190
1191 if (color == NULL)
1192 {
1193 memcpy (&self->overlay_outline_color, &def_overlay_outline_color, sizeof (OverviewColor));
1194 changed = TRUE;
1195 }
1196 else if (!overview_color_equal (color, &self->overlay_outline_color))
1197 {
1198 memcpy (&self->overlay_outline_color, color, sizeof (OverviewColor));
1199 changed = TRUE;
1200 }
1201
1202 if (changed)
1203 {
1204 if (GTK_IS_WIDGET (self->canvas))
1205 gtk_widget_queue_draw (self->canvas);
1206 g_object_notify (G_OBJECT (self), "overlay-outline-color");
1207 }
1208 }
1209
1210 gboolean
overview_scintilla_get_overlay_inverted(OverviewScintilla * self)1211 overview_scintilla_get_overlay_inverted (OverviewScintilla *self)
1212 {
1213 g_return_val_if_fail (OVERVIEW_IS_SCINTILLA (self), FALSE);
1214 return self->overlay_inverted;
1215 }
1216
1217 void
overview_scintilla_set_overlay_inverted(OverviewScintilla * self,gboolean inverted)1218 overview_scintilla_set_overlay_inverted (OverviewScintilla *self,
1219 gboolean inverted)
1220 {
1221 g_return_if_fail (OVERVIEW_IS_SCINTILLA (self));
1222
1223 if (inverted != self->overlay_inverted)
1224 {
1225 self->overlay_inverted = inverted;
1226 overview_scintilla_queue_draw (self);
1227 g_object_notify (G_OBJECT (self), "overlay-inverted");
1228 }
1229 }
1230
1231 gboolean
overview_scintilla_get_double_buffered(OverviewScintilla * self)1232 overview_scintilla_get_double_buffered (OverviewScintilla *self)
1233 {
1234 g_return_val_if_fail (OVERVIEW_IS_SCINTILLA (self), FALSE);
1235 if (GTK_IS_WIDGET (self->canvas))
1236 self->double_buffered = gtk_widget_get_double_buffered (self->canvas);
1237 return self->double_buffered;
1238 }
1239
1240 void
overview_scintilla_set_double_buffered(OverviewScintilla * self,gboolean enabled)1241 overview_scintilla_set_double_buffered (OverviewScintilla *self,
1242 gboolean enabled)
1243 {
1244 g_return_if_fail (OVERVIEW_IS_SCINTILLA (self));
1245
1246 if (enabled != self->double_buffered)
1247 {
1248 self->double_buffered = enabled;
1249 if (GTK_IS_WIDGET (self->canvas))
1250 {
1251 gtk_widget_set_double_buffered (self->canvas, self->double_buffered);
1252 self->double_buffered = gtk_widget_get_double_buffered (self->canvas);
1253 }
1254 if (self->double_buffered == enabled)
1255 g_object_notify (G_OBJECT (self), "double-buffered");
1256 }
1257 }
1258
1259 gint
overview_scintilla_get_scroll_lines(OverviewScintilla * self)1260 overview_scintilla_get_scroll_lines (OverviewScintilla *self)
1261 {
1262 g_return_val_if_fail (OVERVIEW_IS_SCINTILLA (self), -1);
1263 return self->scroll_lines;
1264 }
1265
1266 void
overview_scintilla_set_scroll_lines(OverviewScintilla * self,gint lines)1267 overview_scintilla_set_scroll_lines (OverviewScintilla *self,
1268 gint lines)
1269 {
1270 g_return_if_fail (OVERVIEW_IS_SCINTILLA (self));
1271
1272 if (lines < 0)
1273 lines = OVERVIEW_SCINTILLA_SCROLL_LINES;
1274
1275 if (lines != self->scroll_lines)
1276 {
1277 self->scroll_lines = lines;
1278 g_object_notify (G_OBJECT (self), "scroll-lines");
1279 }
1280 }
1281
1282 gboolean
overview_scintilla_get_show_scrollbar(OverviewScintilla * self)1283 overview_scintilla_get_show_scrollbar (OverviewScintilla *self)
1284 {
1285 g_return_val_if_fail (OVERVIEW_IS_SCINTILLA (self), FALSE);
1286 return self->show_scrollbar;
1287 }
1288
1289 void
overview_scintilla_set_show_scrollbar(OverviewScintilla * self,gboolean show)1290 overview_scintilla_set_show_scrollbar (OverviewScintilla *self,
1291 gboolean show)
1292 {
1293 g_return_if_fail (OVERVIEW_IS_SCINTILLA (self));
1294
1295 if (show != self->show_scrollbar)
1296 {
1297 self->show_scrollbar = show;
1298 sci_send (self->sci, SETVSCROLLBAR, self->show_scrollbar, 0);
1299 gtk_widget_queue_draw (GTK_WIDGET (self->sci));
1300 g_object_notify (G_OBJECT (self), "show-scrollbar");
1301 }
1302 }
1303