1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: t -*- */
2 /* AbiWord
3  * Copyright (C) 2004-2006 Tomas Frydrych <dr.tomas@yahoo.co.uk>
4  * Copyright (C) 2009-2016 Hubert Figuiere
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (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, MA
19  * 02110-1301 USA.
20  */
21 
22 #include "ut_bytebuf.h"
23 
24 #include "gr_UnixCairoGraphics.h"
25 #include "gr_CairoImage.h"
26 #include "gr_Painter.h"
27 #include "gr_UnixImage.h"
28 
29 #include "xap_App.h"
30 #include "xap_EncodingManager.h"
31 #if GTK_CHECK_VERSION(3,0,0)
32 #include "xap_GtkStyle.h"
33 #endif
34 
~GR_UnixCairoGraphicsBase()35 GR_UnixCairoGraphicsBase::~GR_UnixCairoGraphicsBase()
36 {
37 }
38 
39 /*!
40  * Create a new image from the Raster rgba byte buffer defined by pBB.
41  * The dimensions of iWidth and iHeight are in logical units but the image
42  * doesn't scale if the resolution or zoom changes. Instead you must create
43  * a new image.
44  */
createNewImage(const char * pszName,const UT_ByteBuf * pBB,const std::string & mimetype,UT_sint32 iWidth,UT_sint32 iHeight,GR_Image::GRType iType)45 GR_Image* GR_UnixCairoGraphicsBase::createNewImage (const char* pszName,
46 													const UT_ByteBuf* pBB,
47                                                     const std::string& mimetype,
48 													UT_sint32 iWidth,
49 													UT_sint32 iHeight,
50 													GR_Image::GRType iType)
51 {
52    	GR_Image* pImg = NULL;
53 
54 	if (iType == GR_Image::GRT_Raster) {
55 		pImg = new GR_UnixImage(pszName);
56 		pImg->convertFromBuffer(pBB, mimetype, tdu(iWidth), tdu(iHeight));
57 	} else if (iType == GR_Image::GRT_Vector) {
58 		pImg = new GR_RSVGVectorImage(pszName);
59 		pImg->convertFromBuffer(pBB, mimetype, tdu(iWidth), tdu(iHeight));
60 	} else {
61 		UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
62 	}
63 
64    	return pImg;
65 }
66 
GR_UnixCairoGraphicsBase()67 GR_UnixCairoGraphicsBase::GR_UnixCairoGraphicsBase()
68 	: GR_CairoGraphics()
69 {
70 }
71 
GR_UnixCairoGraphicsBase(cairo_t * cr,UT_uint32 iDeviceResolution)72 GR_UnixCairoGraphicsBase::GR_UnixCairoGraphicsBase(cairo_t *cr, UT_uint32 iDeviceResolution)
73 	: GR_CairoGraphics(cr, iDeviceResolution)
74 {
75 }
76 
GR_UnixCairoGraphics(GdkWindow * win,bool double_buffered)77 GR_UnixCairoGraphics::GR_UnixCairoGraphics(GdkWindow * win, bool double_buffered)
78 	: GR_UnixCairoGraphicsBase(),
79 	  m_pWin(win),
80 	  m_double_buffered(double_buffered),
81 	  m_CairoCreated(false),
82 	  m_Painting(false),
83 	  m_Signal(0),
84  	  m_DestroySignal(0),
85 #if GTK_CHECK_VERSION(3,0,0)
86 	  m_Widget(NULL),
87 	  m_styleBg(NULL),
88 	  m_styleHighlight(NULL)
89 #else
90 	  m_Widget(NULL)
91 #endif
92 {
93 	m_cr = NULL;
94 	if (_getWindow())
95 	{
96 		// Set GraphicsExposes so that XCopyArea() causes an expose on
97 		// obscured regions rather than just tiling in the default background.
98 		// TODO: is this still needed with cairo, and if yes can it be emulated
99 		// without having m_pGC any more?
100 		// gdk_gc_set_exposures(m_pGC, 1);
101 		setCursor(GR_CURSOR_DEFAULT);
102 	}
103 }
104 
~GR_UnixCairoGraphics()105 GR_UnixCairoGraphics::~GR_UnixCairoGraphics()
106 {
107 	if (m_Widget) {
108 		g_signal_handler_disconnect (m_Widget, m_Signal);
109 		g_signal_handler_disconnect (m_Widget, m_DestroySignal);
110 	}
111 #if GTK_CHECK_VERSION(3,0,0)
112 	if (m_styleBg) {
113 		g_object_unref(m_styleBg);
114 	}
115 	if (m_styleHighlight) {
116 		g_object_unref(m_styleHighlight);
117 	}
118 #endif
119 }
120 
121 
graphicsAllocator(GR_AllocInfo & info)122 GR_Graphics *   GR_UnixCairoGraphics::graphicsAllocator(GR_AllocInfo& info)
123 {
124 	UT_return_val_if_fail(info.getType() == GRID_UNIX, NULL);
125 	xxx_UT_DEBUGMSG(("GR_CairoGraphics::graphicsAllocator\n"));
126 
127 //	UT_return_val_if_fail(!info.isPrinterGraphics(), NULL);
128 	GR_UnixCairoAllocInfo &AI = (GR_UnixCairoAllocInfo&)info;
129 #if GTK_CHECK_VERSION(3,0,0)
130 	// We disable double buffering on Gtk3 because it doesn't work.
131 	return new GR_UnixCairoGraphics(AI.m_win, false);
132 #else
133 	return new GR_UnixCairoGraphics(AI.m_win, AI.m_double_buffered);
134 #endif
135 }
136 
_convertGdkColor(const GdkColor & c)137 inline UT_RGBColor _convertGdkColor(const GdkColor &c)
138 {
139 	UT_RGBColor color;
140 	color.m_red = c.red >> 8;
141 	color.m_grn = c.green >> 8;
142 	color.m_blu = c.blue >> 8;
143 	return color;
144 }
145 
146 #if GTK_CHECK_VERSION(3,0,0)
_convertGdkRGBA(const GdkRGBA & c)147 inline UT_RGBColor _convertGdkRGBA(const GdkRGBA &c)
148 {
149 	UT_RGBColor color;
150 	color.m_red = c.red * 255;
151 	color.m_grn = c.green * 255;
152 	color.m_blu = c.blue * 255;
153 	return color;
154 }
155 #endif
156 
widget_size_allocate(GtkWidget *,GtkAllocation *,GR_UnixCairoGraphics * me)157 void GR_UnixCairoGraphics::widget_size_allocate(GtkWidget* /*widget*/, GtkAllocation* /*allocation*/, GR_UnixCairoGraphics* me)
158 {
159 	UT_return_if_fail(me);
160 	me->m_clipRectDirty = TRUE;
161 }
162 
widget_destroy(GtkWidget * widget,GR_UnixCairoGraphics * me)163 void GR_UnixCairoGraphics::widget_destroy(GtkWidget* widget, GR_UnixCairoGraphics* me)
164 {
165 	UT_return_if_fail(me && me->m_Widget == widget);
166 	me->m_Widget = NULL;
167 	me->m_Signal = 0;
168 	me->m_DestroySignal = 0;
169 }
170 
initWidget(GtkWidget * widget)171 void GR_UnixCairoGraphics::initWidget(GtkWidget* widget)
172 {
173 	UT_return_if_fail(widget && m_Widget == NULL);
174 	m_Widget = widget;
175 	m_Signal = g_signal_connect_after(G_OBJECT(widget), "size_allocate", G_CALLBACK(widget_size_allocate), this);
176 	m_DestroySignal = g_signal_connect(G_OBJECT(widget), "destroy", G_CALLBACK(widget_destroy), this);
177 }
178 
179 #if GTK_CHECK_VERSION(3,0,0)
180 #define COLOR_MIX 0.67   //COLOR_MIX should be between 0 and 1
181 #define SQUARE(A) (A)*(A)
init3dColors(GtkWidget *)182 void GR_UnixCairoGraphics::init3dColors(GtkWidget* /*w*/)
183 {
184 	if (m_styleBg) {
185 		g_object_unref(m_styleBg);
186 	}
187 	m_styleBg = XAP_GtkStyle_get_style(NULL, "GtkButton"); // "button"
188 	// guess colours
189 	// WHITE
190 	GdkRGBA rgba2;
191 	rgba2.red = 1.;
192 	rgba2.green = 1.;
193 	rgba2.blue = 1.;
194 	rgba2.alpha = 1;
195 	// this is the colour used notably for the the ruler.
196 	// Gray-ish in adwaita, black in Dark theme
197 	m_3dColors[CLR3D_Background] = _convertGdkRGBA(rgba2);
198 
199 	// this is white in Adwaita, and black in a dark theme.
200 	GdkRGBA rgba1;
201 	if (m_styleHighlight) {
202 		g_object_unref(m_styleHighlight);
203 	}
204 	m_styleHighlight = XAP_GtkStyle_get_style(NULL, "GtkTreeView.view"); // "textview.view"
205 	gtk_style_context_get_color (m_styleHighlight, GTK_STATE_FLAG_NORMAL, &rgba1);
206 	m_3dColors[CLR3D_Highlight] = _convertGdkRGBA(rgba1);
207 
208 	// guess colours.
209 	// BLACK
210 	rgba1.red = 0.;
211 	rgba1.green = 0.;
212 	rgba1.blue = 0.;
213 	rgba1.alpha = 1;
214 
215 	GdkRGBA rgba_;
216 	rgba_.alpha = 1.;   // we don't really care, abiword does not use transparency
217 	rgba_.red = rgba1.red*COLOR_MIX + rgba2.red*(1.-COLOR_MIX);
218 	rgba_.green = rgba1.green*COLOR_MIX + rgba2.green*(1.-COLOR_MIX);
219 	rgba_.blue = rgba1.blue*COLOR_MIX + rgba2.blue*(1.-COLOR_MIX);
220 	m_3dColors[CLR3D_BevelUp]    = _convertGdkRGBA(rgba_);
221 
222 	rgba_.red = rgba1.red*(1.-COLOR_MIX) + rgba2.red*COLOR_MIX;
223 	rgba_.green = rgba1.green*(1.-COLOR_MIX) + rgba2.green*COLOR_MIX;
224 	rgba_.blue = rgba1.blue*(1.-COLOR_MIX) + rgba2.blue*COLOR_MIX;
225 	m_3dColors[CLR3D_BevelDown]  = _convertGdkRGBA(rgba_);
226 
227 
228 	GtkStyleContext *text_style = XAP_GtkStyle_get_style(NULL, "GtkLabel.view"); // "label.view"
229 	gtk_style_context_get_color (text_style, GTK_STATE_FLAG_NORMAL, &rgba2);
230 	m_3dColors[CLR3D_Foreground]	= _convertGdkRGBA(rgba2);
231 	g_object_unref(text_style);
232 
233 	m_bHave3DColors = true;
234 }
235 #undef COLOR_MIX
236 #undef SQUARE
237 #else
init3dColors(GtkWidget * w)238 void GR_UnixCairoGraphics::init3dColors(GtkWidget* w)
239 {
240 	init3dColors(w->style);
241 }
init3dColors(GtkStyle * pStyle)242 void GR_UnixCairoGraphics::init3dColors(GtkStyle* pStyle)
243 {
244 	m_3dColors[CLR3D_Foreground] = _convertGdkColor(pStyle->text[GTK_STATE_NORMAL]);
245 	m_3dColors[CLR3D_Background] = _convertGdkColor(pStyle->bg[GTK_STATE_NORMAL]);
246 	m_3dColors[CLR3D_BevelUp]    = _convertGdkColor(pStyle->light[GTK_STATE_NORMAL]);
247 	m_3dColors[CLR3D_BevelDown]  = _convertGdkColor(pStyle->dark[GTK_STATE_NORMAL]);
248 	m_3dColors[CLR3D_Highlight]  = _convertGdkColor(pStyle->bg[GTK_STATE_PRELIGHT]);
249 
250  	m_bHave3DColors = true;
251 }
252 #endif
253 
getGUIFont(void)254 GR_Font * GR_UnixCairoGraphics::getGUIFont(void)
255 {
256 	if (!m_pPFontGUI)
257 	{
258 		// get the font resource
259 #if GTK_CHECK_VERSION(3,0,0)
260 		GtkStyleContext *tempCtxt = gtk_style_context_new();
261 		GtkWidgetPath *path = gtk_widget_path_new();
262 		gtk_widget_path_append_type (path, GTK_TYPE_WINDOW);
263 		gtk_style_context_set_path(tempCtxt, path);
264 		gtk_widget_path_free(path);
265 		PangoFontDescription* fontDesc;
266 		gtk_style_context_get(tempCtxt, GTK_STATE_FLAG_NORMAL, "font", &fontDesc, NULL);
267 		const char *guiFontName = pango_font_description_get_family(fontDesc);
268 #else
269 		GtkStyle *tempStyle = gtk_style_new();
270 		const char *guiFontName = pango_font_description_get_family(tempStyle->font_desc);
271 #endif
272 		if (!guiFontName)
273 			guiFontName = "'Times New Roman'";
274 
275 		UT_UTF8String s = XAP_EncodingManager::get_instance()->getLanguageISOName();
276 
277 		const char * pCountry
278 			= XAP_EncodingManager::get_instance()->getLanguageISOTerritory();
279 
280 		if(pCountry)
281 		{
282 			s += "-";
283 			s += pCountry;
284 		}
285 
286 		m_pPFontGUI = new GR_PangoFont(guiFontName, 11.0, this, s.utf8_str(), true);
287 
288 #if GTK_CHECK_VERSION(3,0,0)
289 		pango_font_description_free(fontDesc);
290 		g_object_unref(G_OBJECT(tempCtxt));
291 #else
292 		g_object_unref(G_OBJECT(tempStyle));
293 #endif
294 
295 		UT_ASSERT(m_pPFontGUI);
296 	}
297 
298 	return m_pPFontGUI;
299 }
300 
301 
setCursor(GR_Graphics::Cursor c)302 void GR_UnixCairoGraphics::setCursor(GR_Graphics::Cursor c)
303 {
304 	if (m_cursor == c)
305 		return;
306 
307 	m_cursor = c;
308 
309 	GdkCursorType cursor_number;
310 
311 	switch (c)
312 	{
313 	default:
314 		UT_ASSERT(UT_NOT_IMPLEMENTED);
315 		/*FALLTHRU*/
316 	case GR_CURSOR_DEFAULT:
317 		cursor_number = GDK_LEFT_PTR;
318 		break;
319 
320 	case GR_CURSOR_IBEAM:
321 		cursor_number = GDK_XTERM;
322 		break;
323 
324 	//I have changed the shape of the arrow so get a consistent
325 	//behaviour in the bidi build; I think the new arrow is better
326 	//for the purpose anyway
327 
328 	case GR_CURSOR_RIGHTARROW:
329 		cursor_number = GDK_SB_RIGHT_ARROW; //GDK_ARROW;
330 		break;
331 
332 	case GR_CURSOR_LEFTARROW:
333 		cursor_number = GDK_SB_LEFT_ARROW; //GDK_LEFT_PTR;
334 		break;
335 
336 	case GR_CURSOR_IMAGE:
337 		cursor_number = GDK_FLEUR;
338 		break;
339 
340 	case GR_CURSOR_IMAGESIZE_NW:
341 		cursor_number = GDK_TOP_LEFT_CORNER;
342 		break;
343 
344 	case GR_CURSOR_IMAGESIZE_N:
345 		cursor_number = GDK_TOP_SIDE;
346 		break;
347 
348 	case GR_CURSOR_IMAGESIZE_NE:
349 		cursor_number = GDK_TOP_RIGHT_CORNER;
350 		break;
351 
352 	case GR_CURSOR_IMAGESIZE_E:
353 		cursor_number = GDK_RIGHT_SIDE;
354 		break;
355 
356 	case GR_CURSOR_IMAGESIZE_SE:
357 		cursor_number = GDK_BOTTOM_RIGHT_CORNER;
358 		break;
359 
360 	case GR_CURSOR_IMAGESIZE_S:
361 		cursor_number = GDK_BOTTOM_SIDE;
362 		break;
363 
364 	case GR_CURSOR_IMAGESIZE_SW:
365 		cursor_number = GDK_BOTTOM_LEFT_CORNER;
366 		break;
367 
368 	case GR_CURSOR_IMAGESIZE_W:
369 		cursor_number = GDK_LEFT_SIDE;
370 		break;
371 
372 	case GR_CURSOR_LEFTRIGHT:
373 		cursor_number = GDK_SB_H_DOUBLE_ARROW;
374 		break;
375 
376 	case GR_CURSOR_UPDOWN:
377 		cursor_number = GDK_SB_V_DOUBLE_ARROW;
378 		break;
379 
380 	case GR_CURSOR_EXCHANGE:
381 		cursor_number = GDK_EXCHANGE;
382 		break;
383 
384 	case GR_CURSOR_GRAB:
385 		cursor_number = GDK_HAND1;
386 		break;
387 
388 	case GR_CURSOR_LINK:
389 		cursor_number = GDK_HAND2;
390 		break;
391 
392 	case GR_CURSOR_WAIT:
393 		cursor_number = GDK_WATCH;
394 		break;
395 
396 	case GR_CURSOR_HLINE_DRAG:
397 		cursor_number = GDK_SB_V_DOUBLE_ARROW;
398 		break;
399 
400 	case GR_CURSOR_VLINE_DRAG:
401 		cursor_number = GDK_SB_H_DOUBLE_ARROW;
402 		break;
403 
404 	case GR_CURSOR_CROSSHAIR:
405 		cursor_number = GDK_CROSSHAIR;
406 		break;
407 
408 	case GR_CURSOR_DOWNARROW:
409 		cursor_number = GDK_SB_DOWN_ARROW;
410 		break;
411 
412 	case GR_CURSOR_DRAGTEXT:
413 		cursor_number = GDK_TARGET;
414 		break;
415 
416 	case GR_CURSOR_COPYTEXT:
417 		cursor_number = GDK_DRAPED_BOX;
418 		break;
419 	}
420 	xxx_UT_DEBUGMSG(("cursor set to %d  gdk %d \n",c,cursor_number));
421 	GdkCursor * cursor = gdk_cursor_new(cursor_number);
422 	gdk_window_set_cursor(m_pWin, cursor);
423 #if GTK_CHECK_VERSION(3,0,0)
424 	g_object_unref(cursor);
425 #else
426 	gdk_cursor_unref(cursor);
427 #endif
428 }
429 
430 
scroll(UT_sint32 dx,UT_sint32 dy)431 void GR_UnixCairoGraphics::scroll(UT_sint32 dx, UT_sint32 dy)
432 {
433 	UT_sint32 oldDY = tdu(getPrevYOffset());
434 	UT_sint32 oldDX = tdu(getPrevXOffset());
435 	UT_sint32 newY = getPrevYOffset() + dy;
436 	UT_sint32 newX = getPrevXOffset() + dx;
437 	UT_sint32 ddx = -(tdu(newX) - oldDX);
438 	UT_sint32 ddy = -(tdu(newY) - oldDY);
439 	setPrevYOffset(newY);
440 	setPrevXOffset(newX);
441 	if(ddx == 0 && ddy == 0)
442 	{
443 		return;
444 	}
445 
446 	disableAllCarets();
447 
448 	UT_sint32 iddy = labs(ddy);
449 	bool bEnableSmooth = XAP_App::getApp()->isSmoothScrollingEnabled();
450 	bEnableSmooth = bEnableSmooth && (iddy < 30) && (ddx == 0);
451 	if(bEnableSmooth)
452 	{
453 		if(ddy < 0)
454 		{
455 			UT_sint32 i = 0;
456 			for(i = 0; i< iddy; i++)
457 			{
458 				gdk_window_scroll(m_pWin,0,-1);
459 			}
460 		}
461 		else
462 		{
463 			UT_sint32 i = 0;
464 			for(i = 0; i< iddy; i++)
465 			{
466 				gdk_window_scroll(m_pWin,0,1);
467 			}
468 		}
469 	}
470 	else
471 	{
472 		gdk_window_scroll(m_pWin,ddx,ddy);
473 	}
474 	enableAllCarets();
475 }
476 
scroll(UT_sint32 x_dest,UT_sint32 y_dest,UT_sint32 x_src,UT_sint32 y_src,G_GNUC_UNUSED UT_sint32 width,G_GNUC_UNUSED UT_sint32 height)477 void GR_UnixCairoGraphics::scroll(UT_sint32 x_dest, UT_sint32 y_dest,
478 						  UT_sint32 x_src, UT_sint32 y_src,
479 						  G_GNUC_UNUSED UT_sint32 width, G_GNUC_UNUSED UT_sint32 height)
480 {
481 #if !GTK_CHECK_VERSION(3,0,0)
482 	GdkGC *gc;
483 
484 	disableAllCarets();
485 	gc = gdk_gc_new(_getWindow());
486    	gdk_draw_drawable(_getWindow(), gc, _getWindow(), tdu(x_src), tdu(y_src),
487 					  tdu(x_dest), tdu(y_dest), tdu(width), tdu(height));
488 	g_object_unref(G_OBJECT(gc)), gc = NULL;
489 	enableAllCarets();
490 #else
491 	scroll(x_src - x_dest, y_src - y_dest);
492 #endif
493 }
494 
_resetClip(void)495 void GR_UnixCairoGraphics::_resetClip(void)
496 {
497 
498 	cairo_reset_clip (m_cr);
499 	xxx_UT_DEBUGMSG(("Reset clip in gtk cairo \n"));
500 }
501 
502 /*!
503  * Take a screenshot of the graphics and convert it to an image.
504  */
genImageFromRectangle(const UT_Rect & rec)505 GR_Image * GR_UnixCairoGraphics::genImageFromRectangle(const UT_Rect &rec)
506 {
507 	UT_sint32 idx = _tduX(rec.left);
508 	UT_sint32 idy = _tduY(rec.top);
509 	UT_sint32 idw = _tduR(rec.width);
510 	UT_sint32 idh = _tduR(rec.height);
511 	UT_return_val_if_fail (idw > 0 && idh > 0 && idx >= 0, NULL);
512 	cairo_surface_flush ( cairo_get_target(m_cr));
513 #if !GTK_CHECK_VERSION(3,0,0)
514 	GdkColormap* cmp = gdk_colormap_get_system();
515 	GdkPixbuf * pix = gdk_pixbuf_get_from_drawable(NULL,
516 												   _getWindow(),
517 												   cmp,
518 												   idx, idy, 0, 0,
519 												   idw, idh);
520 #else
521 	GdkPixbuf * pix = gdk_pixbuf_get_from_window(getWindow(),
522 	                                             idx, idy,
523 	                                             idw, idh);
524 #endif
525 	UT_return_val_if_fail(pix, NULL);
526 
527 	GR_UnixImage * pImg = new GR_UnixImage("ScreenShot");
528 	pImg->setData(pix);
529 	pImg->setDisplaySize(idw,idh);
530 	return pImg;
531 }
532 
_beginPaint()533 void GR_UnixCairoGraphics::_beginPaint()
534 {
535 	UT_ASSERT(m_Painting == false);
536 	GR_CairoGraphics::_beginPaint();
537 
538 	if (m_cr == NULL)
539 	{
540 		UT_ASSERT(m_pWin);
541 		m_cr = gdk_cairo_create (m_pWin);
542 		m_CairoCreated = true;
543 	}
544 
545 #ifndef NDEBUG
546 	/* should only be called inside an expose event, messes up
547 	 * double-buffering and all sorts of other GTK assumptions otherwise
548 	 * we make this extra effort here to track down old wrong code
549 	 */
550 	/* for the time being, ignore it for non-double-buffered widgets that
551 	 * might be very hard to migrate */
552 	if (m_double_buffered)
553 	{
554 		GdkEvent *ev = gtk_get_current_event();
555 		UT_ASSERT(ev);
556 		if (ev)
557 		{
558 			UT_ASSERT(ev->type == GDK_EXPOSE || ev->type == GDK_DAMAGE);
559 			if (ev->type == GDK_EXPOSE || ev->type == GDK_DAMAGE)
560 				UT_ASSERT(ev->expose.window == m_pWin || ev->expose.window == gdk_window_get_effective_parent (m_pWin));
561 		}
562 	}
563 #endif
564 
565 	UT_ASSERT(m_cr);
566 	m_Painting = true;
567 	_initCairo();
568 }
569 
_endPaint()570 void GR_UnixCairoGraphics::_endPaint()
571 {
572 	if (m_CairoCreated)
573 	{
574 		cairo_surface_flush(cairo_get_target(m_cr));
575 		cairo_destroy (m_cr);
576 	}
577 	m_cr = NULL;
578 
579 	m_Painting = false;
580 	m_CairoCreated = false;
581 
582 	GR_CairoGraphics::_endPaint();
583 }
584 
flush(void)585 void GR_UnixCairoGraphics::flush(void)
586 {
587 
588 	if (m_Widget) {
589 		gtk_widget_queue_draw(m_Widget);
590 	}
591 
592 /*
593 	if(m_cr)
594 	{
595 		cairo_surface_flush(cairo_get_target(m_cr));
596 	}
597 */
598 }
599 
queryProperties(GR_Graphics::Properties gp) const600 bool GR_UnixCairoGraphics::queryProperties(GR_Graphics::Properties gp) const
601 {
602 	switch (gp)
603 	{
604 		case DGP_SCREEN:
605 		case DGP_OPAQUEOVERLAY:
606 			return m_pWin != NULL;
607 		case DGP_PAPER:
608 			return false;
609 		default:
610 			UT_ASSERT(0);
611 			return false;
612 	}
613 }
614 
615 #if GTK_CHECK_VERSION(3,0,0)
getColor3D(GR_Color3D name,UT_RGBColor & color)616 bool GR_UnixCairoGraphics::getColor3D(GR_Color3D name, UT_RGBColor &color)
617 {
618 	switch(name) {
619 	case GR_Graphics::CLR3D_Background:
620 	case GR_Graphics::CLR3D_Highlight:
621 		return false;
622 
623 	default:
624 		return GR_CairoGraphics::getColor3D(name, color);
625 	}
626 }
627 
628 /**
629  * This is an override that will use the GtkStyle code to actually render
630  * directly.
631  */
fillRect(GR_Color3D c,UT_sint32 x,UT_sint32 y,UT_sint32 w,UT_sint32 h)632 void GR_UnixCairoGraphics::fillRect(GR_Color3D c, UT_sint32 x, UT_sint32 y,
633                                     UT_sint32 w, UT_sint32 h)
634 {
635 	switch(c) {
636 	case GR_Graphics::CLR3D_Background:
637 	case GR_Graphics::CLR3D_Highlight:
638 	{
639 		if (m_cr == NULL) {
640 			return;
641 		}
642 		_setProps();
643 		cairo_save (m_cr);
644 
645 		GtkStyleContext *context = NULL;
646 		switch(c) {
647 		case GR_Graphics::CLR3D_Background:
648 			context = m_styleBg;
649 			break;
650 		case GR_Graphics::CLR3D_Highlight:
651 			context = m_styleHighlight;
652 			break;
653 		default:
654 			UT_ASSERT(0);
655 			return;
656 		}
657 		gtk_render_background (context, m_cr, tdu(x), tdu(y), tdu(w), tdu(h));
658 		gtk_render_frame (context, m_cr, tdu(x), tdu(y), tdu(w), tdu(h));
659 		cairo_restore (m_cr);
660 		break;
661 	}
662 	default:
663 		GR_CairoGraphics::fillRect(c, x, y, w, h);
664 		return;
665 	}
666 }
667 #endif
668