Theme engine using TQt for GTK+ 3.x
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

tdegtk-cairo-support.c 44KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346
  1. /* The TdeGtk Theming Engine for Gtk+.
  2. * Copyright (C) 2011 Canonical Ltd
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free
  16. * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
  17. * MA 02110-1301, USA.
  18. *
  19. * Authored by Andrea Cimitan <andrea.cimitan@canonical.com>
  20. *
  21. */
  22. #include <cairo.h>
  23. #include <gtk/gtk.h>
  24. #include "gtkroundedboxprivate.h"
  25. #include "tdegtk-cairo-support.h"
  26. #include "tdegtk-support.h"
  27. #include "tdegtk-types.h"
  28. /* apply default color */
  29. static void
  30. apply_default_color (GdkRGBA *colors[4],
  31. GdkRGBA *default_color)
  32. {
  33. gint i;
  34. for (i = 0; i < 4; i++)
  35. if (tdegtk_gdk_rgba_is_default (colors[i]))
  36. *colors[i] = *default_color;
  37. }
  38. /* set the border sides to 0 using hidden_side */
  39. static void
  40. hide_border_sides (GtkBorder *border,
  41. guint hidden_side)
  42. {
  43. if (hidden_side & SIDE_TOP)
  44. border->top = 0;
  45. if (hidden_side & SIDE_RIGHT)
  46. border->right = 0;
  47. if (hidden_side & SIDE_BOTTOM)
  48. border->bottom = 0;
  49. if (hidden_side & SIDE_LEFT)
  50. border->left = 0;
  51. }
  52. /* shrink coordinate using GtkBorder */
  53. static void
  54. shrink_with_border (GtkBorder *border,
  55. gdouble *x,
  56. gdouble *y,
  57. gdouble *width,
  58. gdouble *height)
  59. {
  60. *x += border->left;
  61. *y += border->top;
  62. *width -= border->left + border->right;
  63. *height -= border->top + border->bottom;
  64. }
  65. /* draw the background */
  66. static void
  67. draw_background (GtkThemingEngine *engine,
  68. cairo_t *cr,
  69. gdouble x,
  70. gdouble y,
  71. gdouble width,
  72. gdouble height,
  73. guint hidden_side,
  74. GtkJunctionSides junction)
  75. {
  76. GdkRGBA bg_color;
  77. GtkBorder border;
  78. GtkRoundedBox border_box;
  79. GtkStateFlags state;
  80. cairo_pattern_t *bg_pat;
  81. gdouble progress;
  82. gboolean running;
  83. state = gtk_theming_engine_get_state (engine);
  84. gtk_theming_engine_get (engine, state,
  85. "background-image", &bg_pat,
  86. NULL);
  87. gtk_theming_engine_get_background_color (engine, state, &bg_color);
  88. gtk_theming_engine_get_border (engine, state, &border);
  89. hide_border_sides (&border, hidden_side);
  90. running = gtk_theming_engine_state_is_running (engine, GTK_STATE_PRELIGHT, &progress);
  91. cairo_save (cr);
  92. cairo_translate (cr, x, y);
  93. /* clear cr if we can draw directly on the background */
  94. if (gtk_theming_engine_has_class (engine, "background"))
  95. {
  96. cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0); /* transparent */
  97. cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
  98. cairo_paint (cr);
  99. }
  100. if (running)
  101. {
  102. GdkRGBA other_bg;
  103. GtkStateFlags other_state;
  104. cairo_pattern_t *new_pat = NULL;
  105. cairo_pattern_t *other_pat;
  106. if (state & GTK_STATE_FLAG_PRELIGHT)
  107. {
  108. other_state = state & ~(GTK_STATE_FLAG_PRELIGHT);
  109. /* useful math function to use for a pulse loop animation could be
  110. * progress = 1 - MAX (1 - fabs ((progress - 0.5)*2), 0);
  111. * but we need to handle the not-running case (once animation finished),
  112. * otherwise the last frame will be the PRELIGHT at full opacity. */
  113. progress = 1 - progress;
  114. }
  115. else
  116. other_state = state | GTK_STATE_FLAG_PRELIGHT;
  117. gtk_theming_engine_get (engine, other_state,
  118. "background-image", &other_pat,
  119. NULL);
  120. gtk_theming_engine_get_background_color (engine, other_state, &other_bg);
  121. if (bg_pat && other_pat)
  122. {
  123. /* two patterns */
  124. cairo_pattern_type_t type, other_type;
  125. gint n0, n1;
  126. cairo_pattern_get_color_stop_count (bg_pat, &n0);
  127. cairo_pattern_get_color_stop_count (other_pat, &n1);
  128. type = cairo_pattern_get_type (bg_pat);
  129. other_type = cairo_pattern_get_type (other_pat);
  130. if (type == other_type && n0 == n1)
  131. {
  132. /* two similar patterns, blend them point by point */
  133. gdouble offset0, red0, green0, blue0, alpha0;
  134. gdouble offset1, red1, green1, blue1, alpha1;
  135. gdouble x00, x01, y00, y01, x10, x11, y10, y11;
  136. gdouble r00, r01, r10, r11;
  137. gint i;
  138. if (type == CAIRO_PATTERN_TYPE_LINEAR)
  139. {
  140. cairo_pattern_get_linear_points (bg_pat, &x00, &y00, &x01, &y01);
  141. cairo_pattern_get_linear_points (other_pat, &x10, &y10, &x11, &y11);
  142. new_pat = cairo_pattern_create_linear (x00 + (x10 - x00) * progress,
  143. y00 + (y10 - y00) * progress,
  144. x01 + (x11 - x01) * progress,
  145. y01 + (y11 - y01) * progress);
  146. }
  147. else
  148. {
  149. cairo_pattern_get_radial_circles (bg_pat, &x00, &y00, &r00, &x01, &y01, &r01);
  150. cairo_pattern_get_radial_circles (other_pat, &x10, &y10, &r10, &x11, &y11, &r11);
  151. new_pat = cairo_pattern_create_radial (x00 + (x10 - x00) * progress,
  152. y00 + (y10 - y00) * progress,
  153. r00 + (r10 - r00) * progress,
  154. x01 + (x11 - x01) * progress,
  155. y01 + (y11 - y01) * progress,
  156. r01 + (r11 - r01) * progress);
  157. }
  158. cairo_pattern_set_filter (new_pat, CAIRO_FILTER_FAST);
  159. i = 0;
  160. while (i < n0 && i < n1)
  161. {
  162. cairo_pattern_get_color_stop_rgba (bg_pat, i,
  163. &offset0,
  164. &red0, &green0, &blue0,
  165. &alpha0);
  166. cairo_pattern_get_color_stop_rgba (other_pat, i,
  167. &offset1,
  168. &red1, &green1, &blue1,
  169. &alpha1);
  170. cairo_pattern_add_color_stop_rgba (new_pat,
  171. offset0 + ((offset1 - offset0) * progress),
  172. red0 + ((red1 - red0) * progress),
  173. green0 + ((green1 - green0) * progress),
  174. blue0 + ((blue1 - blue0) * progress),
  175. alpha0 + ((alpha1 - alpha0) * progress));
  176. i++;
  177. }
  178. }
  179. else
  180. {
  181. /* two different patterns, paint them with alpha */
  182. cairo_save (cr);
  183. cairo_reset_clip (cr);
  184. cairo_rectangle (cr, 0, 0, width, height);
  185. cairo_clip (cr);
  186. cairo_push_group (cr);
  187. cairo_scale (cr, width, height);
  188. cairo_set_source (cr, other_pat);
  189. cairo_paint_with_alpha (cr, progress);
  190. cairo_set_source (cr, bg_pat);
  191. cairo_paint_with_alpha (cr, 1.0 - progress);
  192. new_pat = cairo_pop_group (cr);
  193. cairo_restore (cr);
  194. }
  195. }
  196. else if (bg_pat || other_pat)
  197. {
  198. /* only one pattern, blend it with a color */
  199. const GdkRGBA *c;
  200. cairo_pattern_t *p;
  201. gdouble x0, y0, x1, y1, r0, r1;
  202. gint n, i;
  203. if (bg_pat)
  204. {
  205. p = bg_pat;
  206. c = &other_bg;
  207. progress = 1 - progress;
  208. }
  209. else
  210. {
  211. p = other_pat;
  212. c = &bg_color;
  213. }
  214. if (cairo_pattern_get_type (p) == CAIRO_PATTERN_TYPE_LINEAR)
  215. {
  216. cairo_pattern_get_linear_points (p, &x0, &y0, &x1, &y1);
  217. new_pat = cairo_pattern_create_linear (x0, y0, x1, y1);
  218. }
  219. else
  220. {
  221. cairo_pattern_get_radial_circles (p, &x0, &y0, &r0, &x1, &y1, &r1);
  222. new_pat = cairo_pattern_create_radial (x0, y0, r0, x1, y1, r1);
  223. }
  224. cairo_pattern_get_color_stop_count (p, &n);
  225. for (i = 0; i < n; i++)
  226. {
  227. gdouble red1, green1, blue1, alpha1;
  228. gdouble offset;
  229. cairo_pattern_get_color_stop_rgba (p, i,
  230. &offset,
  231. &red1, &green1, &blue1,
  232. &alpha1);
  233. cairo_pattern_add_color_stop_rgba (new_pat, offset,
  234. c->red + ((red1 - c->red) * progress),
  235. c->green + ((green1 - c->green) * progress),
  236. c->blue + ((blue1 - c->blue) * progress),
  237. c->alpha + ((alpha1 - c->alpha) * progress));
  238. }
  239. }
  240. else
  241. {
  242. /* just colors, create a new pattern blending them */
  243. new_pat = cairo_pattern_create_rgba (CLAMP (bg_color.red + ((other_bg.red - bg_color.red) * progress), 0, 1),
  244. CLAMP (bg_color.green + ((other_bg.green - bg_color.green) * progress), 0, 1),
  245. CLAMP (bg_color.blue + ((other_bg.blue - bg_color.blue) * progress), 0, 1),
  246. CLAMP (bg_color.alpha + ((other_bg.alpha - bg_color.alpha) * progress), 0, 1));
  247. }
  248. if (new_pat)
  249. {
  250. /* replace pattern to use */
  251. cairo_pattern_destroy (bg_pat);
  252. bg_pat = new_pat;
  253. }
  254. if (other_pat)
  255. cairo_pattern_destroy (other_pat);
  256. }
  257. /* create the path to fill */
  258. _gtk_rounded_box_init_rect (&border_box, 0, 0, width, height);
  259. _gtk_rounded_box_apply_border_radius (&border_box, engine, state, junction);
  260. _gtk_rounded_box_shrink (&border_box, border.top, border.right, border.bottom, border.left);
  261. _gtk_rounded_box_path (&border_box, cr);
  262. if (bg_pat)
  263. {
  264. /* pattern */
  265. cairo_scale (cr, width, height);
  266. cairo_set_source (cr, bg_pat);
  267. cairo_scale (cr, 1.0 / width, 1.0 / height);
  268. }
  269. else
  270. /* one color */
  271. gdk_cairo_set_source_rgba (cr, &bg_color);
  272. cairo_fill (cr);
  273. if (bg_pat)
  274. cairo_pattern_destroy (bg_pat);
  275. cairo_restore (cr);
  276. }
  277. /* draw the inner glow */
  278. static void
  279. draw_glow (GtkThemingEngine *engine,
  280. cairo_t *cr,
  281. gdouble x,
  282. gdouble y,
  283. gdouble width,
  284. gdouble height,
  285. guint hidden_side,
  286. GtkJunctionSides junction)
  287. {
  288. }
  289. /* draw a repeated texture */
  290. static void
  291. draw_texture (GtkThemingEngine *engine,
  292. cairo_t *cr,
  293. gdouble x,
  294. gdouble y,
  295. gdouble width,
  296. gdouble height,
  297. guint hidden_side,
  298. GtkJunctionSides junction)
  299. {
  300. GtkStateFlags state;
  301. GValue value = { 0, };
  302. cairo_pattern_t *texture = NULL;
  303. cairo_surface_t *surface = NULL;
  304. state = gtk_theming_engine_get_state (engine);
  305. gtk_theming_engine_get_property (engine, "-tdegtk-background-texture", state, &value);
  306. if (!G_VALUE_HOLDS_BOXED (&value))
  307. return;
  308. texture = g_value_dup_boxed (&value);
  309. g_value_unset (&value);
  310. if (texture != NULL)
  311. cairo_pattern_get_surface (texture, &surface);
  312. if (surface != NULL)
  313. {
  314. GtkBorder border;
  315. GtkRoundedBox border_box;
  316. cairo_pattern_t *pat;
  317. gtk_theming_engine_get_border (engine, state, &border);
  318. hide_border_sides (&border, hidden_side);
  319. cairo_save (cr);
  320. cairo_translate (cr, x, y);
  321. /* create the path to fill */
  322. _gtk_rounded_box_init_rect (&border_box, 0, 0, width, height);
  323. _gtk_rounded_box_apply_border_radius (&border_box, engine, state, junction);
  324. _gtk_rounded_box_shrink (&border_box, border.top, border.right, border.bottom, border.left);
  325. _gtk_rounded_box_path (&border_box, cr);
  326. pat = cairo_pattern_create_for_surface (surface);
  327. cairo_pattern_set_extend (pat, CAIRO_EXTEND_REPEAT);
  328. cairo_set_source (cr, pat);
  329. cairo_fill (cr);
  330. cairo_restore (cr);
  331. cairo_pattern_destroy (pat);
  332. }
  333. if (texture != NULL)
  334. cairo_pattern_destroy (texture);
  335. }
  336. void
  337. tdegtk_cairo_draw_background (GtkThemingEngine *engine,
  338. cairo_t *cr,
  339. gdouble x,
  340. gdouble y,
  341. gdouble width,
  342. gdouble height,
  343. guint hidden_side,
  344. GtkJunctionSides junction)
  345. {
  346. GtkBorder *outer_border;
  347. GtkStateFlags state;
  348. state = gtk_theming_engine_get_state (engine);
  349. gtk_theming_engine_get (engine, state,
  350. "-tdegtk-outer-stroke-width", &outer_border,
  351. NULL);
  352. hide_border_sides (outer_border, hidden_side);
  353. shrink_with_border (outer_border, &x, &y, &width, &height);
  354. /* first layer, background */
  355. draw_background (engine, cr,
  356. x, y,
  357. width, height,
  358. hidden_side, junction);
  359. /* second layer, glow */
  360. draw_glow (engine, cr,
  361. x, y,
  362. width, height,
  363. hidden_side, junction);
  364. /* third layer, texture */
  365. draw_texture (engine, cr,
  366. x, y,
  367. width, height,
  368. hidden_side, junction);
  369. gtk_border_free (outer_border);
  370. }
  371. /* shade a color */
  372. static void
  373. color_shade (const GdkRGBA *color,
  374. gdouble factor,
  375. GdkRGBA *color_return)
  376. {
  377. GtkSymbolicColor *literal, *shade;
  378. literal = gtk_symbolic_color_new_literal (color);
  379. shade = gtk_symbolic_color_new_shade (literal, factor);
  380. gtk_symbolic_color_unref (literal);
  381. gtk_symbolic_color_resolve (shade, NULL, color_return);
  382. gtk_symbolic_color_unref (shade);
  383. }
  384. /* draw the border */
  385. static void
  386. draw_border (GtkThemingEngine *engine,
  387. cairo_t *cr,
  388. gdouble x,
  389. gdouble y,
  390. gdouble width,
  391. gdouble height,
  392. guint hidden_side,
  393. GtkJunctionSides junction)
  394. {
  395. GdkRGBA *colors[4];
  396. GtkBorder border;
  397. GtkBorderStyle border_style;
  398. GtkRoundedBox border_box, padding_box;
  399. GtkStateFlags state;
  400. cairo_pattern_t *border_pat;
  401. gboolean running;
  402. gdouble progress;
  403. static const guint current_side[4] = { SIDE_TOP, SIDE_RIGHT, SIDE_BOTTOM, SIDE_LEFT };
  404. guint i, j;
  405. state = gtk_theming_engine_get_state (engine);
  406. gtk_theming_engine_get (engine, state,
  407. "border-style", &border_style,
  408. "border-top-color", &colors[0],
  409. "border-right-color", &colors[1],
  410. "border-bottom-color", &colors[2],
  411. "border-left-color", &colors[3],
  412. "-tdegtk-border-gradient", &border_pat,
  413. NULL);
  414. gtk_theming_engine_get_border (engine, state, &border);
  415. hide_border_sides (&border, hidden_side);
  416. running = gtk_theming_engine_state_is_running (engine, GTK_STATE_PRELIGHT, &progress);
  417. cairo_save (cr);
  418. cairo_translate (cr, x, y);
  419. if (running)
  420. {
  421. GtkStateFlags other_state;
  422. cairo_pattern_t *new_pat = NULL;
  423. cairo_pattern_t *other_pat;
  424. if (state & GTK_STATE_FLAG_PRELIGHT)
  425. {
  426. other_state = state & ~(GTK_STATE_FLAG_PRELIGHT);
  427. progress = 1 - progress;
  428. }
  429. else
  430. other_state = state | GTK_STATE_FLAG_PRELIGHT;
  431. gtk_theming_engine_get (engine, other_state,
  432. "-tdegtk-border-gradient", &other_pat,
  433. NULL);
  434. if (border_pat && other_pat)
  435. {
  436. /* two patterns */
  437. cairo_pattern_type_t type, other_type;
  438. gint n0, n1;
  439. cairo_pattern_get_color_stop_count (border_pat, &n0);
  440. cairo_pattern_get_color_stop_count (other_pat, &n1);
  441. type = cairo_pattern_get_type (border_pat);
  442. other_type = cairo_pattern_get_type (other_pat);
  443. if (type == other_type && n0 == n1)
  444. {
  445. /* two similar patterns, blend them point by point */
  446. gdouble offset0, red0, green0, blue0, alpha0;
  447. gdouble offset1, red1, green1, blue1, alpha1;
  448. gdouble x00, x01, y00, y01, x10, x11, y10, y11;
  449. gdouble r00, r01, r10, r11;
  450. gint i;
  451. if (type == CAIRO_PATTERN_TYPE_LINEAR)
  452. {
  453. cairo_pattern_get_linear_points (border_pat, &x00, &y00, &x01, &y01);
  454. cairo_pattern_get_linear_points (other_pat, &x10, &y10, &x11, &y11);
  455. new_pat = cairo_pattern_create_linear (x00 + (x10 - x00) * progress,
  456. y00 + (y10 - y00) * progress,
  457. x01 + (x11 - x01) * progress,
  458. y01 + (y11 - y01) * progress);
  459. }
  460. else
  461. {
  462. cairo_pattern_get_radial_circles (border_pat, &x00, &y00, &r00, &x01, &y01, &r01);
  463. cairo_pattern_get_radial_circles (other_pat, &x10, &y10, &r10, &x11, &y11, &r11);
  464. new_pat = cairo_pattern_create_radial (x00 + (x10 - x00) * progress,
  465. y00 + (y10 - y00) * progress,
  466. r00 + (r10 - r00) * progress,
  467. x01 + (x11 - x01) * progress,
  468. y01 + (y11 - y01) * progress,
  469. r01 + (r11 - r01) * progress);
  470. }
  471. cairo_pattern_set_filter (new_pat, CAIRO_FILTER_FAST);
  472. i = 0;
  473. while (i < n0 && i < n1)
  474. {
  475. cairo_pattern_get_color_stop_rgba (border_pat, i,
  476. &offset0,
  477. &red0, &green0, &blue0,
  478. &alpha0);
  479. cairo_pattern_get_color_stop_rgba (other_pat, i,
  480. &offset1,
  481. &red1, &green1, &blue1,
  482. &alpha1);
  483. cairo_pattern_add_color_stop_rgba (new_pat,
  484. offset0 + ((offset1 - offset0) * progress),
  485. red0 + ((red1 - red0) * progress),
  486. green0 + ((green1 - green0) * progress),
  487. blue0 + ((blue1 - blue0) * progress),
  488. alpha0 + ((alpha1 - alpha0) * progress));
  489. i++;
  490. }
  491. }
  492. else
  493. {
  494. /* two different patterns, paint them with alpha */
  495. cairo_save (cr);
  496. cairo_reset_clip (cr);
  497. cairo_rectangle (cr, 0, 0, width, height);
  498. cairo_clip (cr);
  499. cairo_push_group (cr);
  500. cairo_scale (cr, width, height);
  501. cairo_set_source (cr, other_pat);
  502. cairo_paint_with_alpha (cr, progress);
  503. cairo_set_source (cr, border_pat);
  504. cairo_paint_with_alpha (cr, 1.0 - progress);
  505. new_pat = cairo_pop_group (cr);
  506. cairo_restore (cr);
  507. }
  508. }
  509. else if (border_pat || other_pat)
  510. {
  511. /* one pattern, blend it with a color */
  512. const GdkRGBA *c;
  513. cairo_pattern_t *p;
  514. gdouble x0, y0, x1, y1, r0, r1;
  515. gint n, i;
  516. if (border_pat)
  517. {
  518. GdkRGBA other_color;
  519. gtk_theming_engine_get_border_color (engine, other_state, &other_color);
  520. p = border_pat;
  521. c = &other_color;
  522. progress = 1 - progress;
  523. }
  524. else
  525. {
  526. GdkRGBA border_color;
  527. gtk_theming_engine_get_border_color (engine, state, &border_color);
  528. p = other_pat;
  529. c = &border_color;
  530. }
  531. if (cairo_pattern_get_type (p) == CAIRO_PATTERN_TYPE_LINEAR)
  532. {
  533. cairo_pattern_get_linear_points (p, &x0, &y0, &x1, &y1);
  534. new_pat = cairo_pattern_create_linear (x0, y0, x1, y1);
  535. }
  536. else
  537. {
  538. cairo_pattern_get_radial_circles (p, &x0, &y0, &r0, &x1, &y1, &r1);
  539. new_pat = cairo_pattern_create_radial (x0, y0, r0, x1, y1, r1);
  540. }
  541. cairo_pattern_get_color_stop_count (p, &n);
  542. for (i = 0; i < n; i++)
  543. {
  544. gdouble red1, green1, blue1, alpha1;
  545. gdouble offset;
  546. cairo_pattern_get_color_stop_rgba (p, i,
  547. &offset,
  548. &red1, &green1, &blue1,
  549. &alpha1);
  550. cairo_pattern_add_color_stop_rgba (new_pat, offset,
  551. c->red + ((red1 - c->red) * progress),
  552. c->green + ((green1 - c->green) * progress),
  553. c->blue + ((blue1 - c->blue) * progress),
  554. c->alpha + ((alpha1 - c->alpha) * progress));
  555. }
  556. }
  557. else
  558. {
  559. /* just colors, create new colors blending them */
  560. GdkRGBA *other_colors[4];
  561. gtk_theming_engine_get (engine, other_state,
  562. "border-top-color", &other_colors[0],
  563. "border-right-color", &other_colors[1],
  564. "border-bottom-color", &other_colors[2],
  565. "border-left-color", &other_colors[3],
  566. NULL);
  567. for (i = 0; i < 4; i++)
  568. {
  569. colors[i]->red = CLAMP (colors[i]->red + ((other_colors[i]->red - colors[i]->red) * progress), 0, 1);
  570. colors[i]->green = CLAMP (colors[i]->green + ((other_colors[i]->green - colors[i]->green) * progress), 0, 1);
  571. colors[i]->blue = CLAMP (colors[i]->blue + ((other_colors[i]->blue - colors[i]->blue) * progress), 0, 1);
  572. colors[i]->alpha = CLAMP (colors[i]->alpha + ((other_colors[i]->alpha - colors[i]->alpha) * progress), 0, 1);
  573. gdk_rgba_free (other_colors[i]);
  574. }
  575. }
  576. if (new_pat)
  577. {
  578. /* replace pattern to use */
  579. cairo_pattern_destroy (border_pat);
  580. border_pat = new_pat;
  581. }
  582. if (other_pat)
  583. cairo_pattern_destroy (other_pat);
  584. }
  585. switch (border_style)
  586. {
  587. default:
  588. g_assert_not_reached ();
  589. case GTK_BORDER_STYLE_NONE:
  590. case GTK_BORDER_STYLE_SOLID:
  591. break;
  592. case GTK_BORDER_STYLE_INSET:
  593. color_shade (colors[1], 1.8, colors[1]);
  594. color_shade (colors[2], 1.8, colors[2]);
  595. break;
  596. case GTK_BORDER_STYLE_OUTSET:
  597. color_shade (colors[0], 1.8, colors[0]);
  598. color_shade (colors[3], 1.8, colors[3]);
  599. break;
  600. }
  601. /* create the path to fill */
  602. _gtk_rounded_box_init_rect (&border_box, 0, 0, width, height);
  603. _gtk_rounded_box_apply_border_radius (&border_box, engine, state, junction);
  604. padding_box = border_box;
  605. _gtk_rounded_box_shrink (&padding_box, border.top, border.right, border.bottom, border.left);
  606. cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
  607. switch (border_style)
  608. {
  609. default:
  610. g_assert_not_reached ();
  611. case GTK_BORDER_STYLE_NONE:
  612. break;
  613. case GTK_BORDER_STYLE_SOLID:
  614. case GTK_BORDER_STYLE_INSET:
  615. case GTK_BORDER_STYLE_OUTSET:
  616. if (border_pat)
  617. {
  618. /* pattern */
  619. cairo_scale (cr, width, height);
  620. cairo_set_source (cr, border_pat);
  621. cairo_scale (cr, 1.0 / width, 1.0 / height);
  622. _gtk_rounded_box_path (&border_box, cr);
  623. _gtk_rounded_box_path (&padding_box, cr);
  624. cairo_fill (cr);
  625. }
  626. else if (gdk_rgba_equal (colors[0], colors[1]) &&
  627. gdk_rgba_equal (colors[0], colors[2]) &&
  628. gdk_rgba_equal (colors[0], colors[3]))
  629. {
  630. /* one color */
  631. gdk_cairo_set_source_rgba (cr, colors[0]);
  632. _gtk_rounded_box_path (&border_box, cr);
  633. _gtk_rounded_box_path (&padding_box, cr);
  634. cairo_fill (cr);
  635. }
  636. else
  637. {
  638. for (i = 0; i < 4; i++)
  639. {
  640. /* different colors */
  641. if (hidden_side & current_side[i])
  642. continue;
  643. for (j = 0; j < 4; j++)
  644. {
  645. if (hidden_side & current_side[j])
  646. continue;
  647. if (i == j ||
  648. gdk_rgba_equal (colors[i], colors[j]))
  649. {
  650. /* we were already painted when i == j */
  651. if (i > j)
  652. break;
  653. if (j == 0)
  654. _gtk_rounded_box_path_top (&border_box, &padding_box, cr);
  655. else if (j == 1)
  656. _gtk_rounded_box_path_right (&border_box, &padding_box, cr);
  657. else if (j == 2)
  658. _gtk_rounded_box_path_bottom (&border_box, &padding_box, cr);
  659. else if (j == 3)
  660. _gtk_rounded_box_path_left (&border_box, &padding_box, cr);
  661. }
  662. }
  663. /* we were already painted when i == j */
  664. if (i > j)
  665. continue;
  666. gdk_cairo_set_source_rgba (cr, colors[i]);
  667. cairo_fill (cr);
  668. }
  669. }
  670. break;
  671. }
  672. cairo_restore (cr);
  673. if (border_pat)
  674. cairo_pattern_destroy (border_pat);
  675. for (i = 0; i < 4; i++)
  676. gdk_rgba_free (colors[i]);
  677. }
  678. /* draw the inner stroke */
  679. static void
  680. draw_inner_stroke (GtkThemingEngine *engine,
  681. cairo_t *cr,
  682. gdouble x,
  683. gdouble y,
  684. gdouble width,
  685. gdouble height,
  686. guint hidden_side,
  687. GtkJunctionSides junction)
  688. {
  689. GdkRGBA *colors[4];
  690. GdkRGBA *inner_stroke_color;
  691. GtkBorder *inner_border;
  692. GtkRoundedBox border_box, padding_box;
  693. GtkStateFlags state;
  694. cairo_pattern_t *inner_stroke_pat;
  695. static const guint current_side[4] = { SIDE_TOP, SIDE_RIGHT, SIDE_BOTTOM, SIDE_LEFT };
  696. guint i, j;
  697. state = gtk_theming_engine_get_state (engine);
  698. gtk_theming_engine_get (engine, state,
  699. "-tdegtk-inner-stroke-color", &inner_stroke_color,
  700. "-tdegtk-inner-stroke-top-color", &colors[0],
  701. "-tdegtk-inner-stroke-right-color", &colors[1],
  702. "-tdegtk-inner-stroke-bottom-color", &colors[2],
  703. "-tdegtk-inner-stroke-left-color", &colors[3],
  704. "-tdegtk-inner-stroke-gradient", &inner_stroke_pat,
  705. "-tdegtk-inner-stroke-width", &inner_border,
  706. NULL);
  707. hide_border_sides (inner_border, hidden_side);
  708. if (tdegtk_gtk_border_is_zero (inner_border))
  709. goto end_draw_inner_stroke;
  710. apply_default_color (colors, inner_stroke_color);
  711. cairo_save (cr);
  712. cairo_translate (cr, x, y);
  713. /* create the path to fill */
  714. _gtk_rounded_box_init_rect (&border_box, 0, 0, width, height);
  715. _gtk_rounded_box_apply_border_radius (&border_box, engine, state, junction);
  716. padding_box = border_box;
  717. _gtk_rounded_box_shrink (&padding_box, inner_border->top,
  718. inner_border->right,
  719. inner_border->bottom,
  720. inner_border->left);
  721. cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
  722. if (inner_stroke_pat)
  723. {
  724. /* pattern */
  725. cairo_scale (cr, width, height);
  726. cairo_set_source (cr, inner_stroke_pat);
  727. cairo_scale (cr, 1.0 / width, 1.0 / height);
  728. _gtk_rounded_box_path (&border_box, cr);
  729. _gtk_rounded_box_path (&padding_box, cr);
  730. cairo_fill (cr);
  731. }
  732. else if (gdk_rgba_equal (colors[0], colors[1]) &&
  733. gdk_rgba_equal (colors[0], colors[2]) &&
  734. gdk_rgba_equal (colors[0], colors[3]))
  735. {
  736. /* one color */
  737. gdk_cairo_set_source_rgba (cr, colors[0]);
  738. _gtk_rounded_box_path (&border_box, cr);
  739. _gtk_rounded_box_path (&padding_box, cr);
  740. cairo_fill (cr);
  741. }
  742. else
  743. {
  744. /* different colors */
  745. for (i = 0; i < 4; i++)
  746. {
  747. if (hidden_side & current_side[i])
  748. continue;
  749. for (j = 0; j < 4; j++)
  750. {
  751. if (hidden_side & current_side[j])
  752. continue;
  753. if (i == j ||
  754. gdk_rgba_equal (colors[i], colors[j]))
  755. {
  756. /* we were already painted when i == j */
  757. if (i > j)
  758. break;
  759. if (j == 0)
  760. _gtk_rounded_box_path_top (&border_box, &padding_box, cr);
  761. else if (j == 1)
  762. _gtk_rounded_box_path_right (&border_box, &padding_box, cr);
  763. else if (j == 2)
  764. _gtk_rounded_box_path_bottom (&border_box, &padding_box, cr);
  765. else if (j == 3)
  766. _gtk_rounded_box_path_left (&border_box, &padding_box, cr);
  767. }
  768. }
  769. /* we were already painted when i == j */
  770. if (i > j)
  771. continue;
  772. gdk_cairo_set_source_rgba (cr, colors[i]);
  773. cairo_fill (cr);
  774. }
  775. }
  776. cairo_restore (cr);
  777. end_draw_inner_stroke:
  778. gtk_border_free (inner_border);
  779. if (inner_stroke_pat != NULL)
  780. cairo_pattern_destroy (inner_stroke_pat);
  781. gdk_rgba_free (inner_stroke_color);
  782. for (i = 0; i < 4; i++)
  783. gdk_rgba_free (colors[i]);
  784. }
  785. /* draw the outer stroke */
  786. static void
  787. draw_outer_stroke (GtkThemingEngine *engine,
  788. cairo_t *cr,
  789. gdouble x,
  790. gdouble y,
  791. gdouble width,
  792. gdouble height,
  793. guint hidden_side,
  794. GtkJunctionSides junction)
  795. {
  796. GdkRGBA *outer_stroke_color;
  797. GdkRGBA *colors[4];
  798. GtkBorder *outer_border;
  799. GtkRoundedBox border_box, padding_box;
  800. GtkStateFlags state;
  801. cairo_pattern_t *outer_stroke_pat;
  802. static const guint current_side[4] = { SIDE_TOP, SIDE_RIGHT, SIDE_BOTTOM, SIDE_LEFT };
  803. guint i, j;
  804. state = gtk_theming_engine_get_state (engine);
  805. gtk_theming_engine_get (engine, state,
  806. "-tdegtk-outer-stroke-color", &outer_stroke_color,
  807. "-tdegtk-outer-stroke-top-color", &colors[0],
  808. "-tdegtk-outer-stroke-right-color", &colors[1],
  809. "-tdegtk-outer-stroke-bottom-color", &colors[2],
  810. "-tdegtk-outer-stroke-left-color", &colors[3],
  811. "-tdegtk-outer-stroke-gradient", &outer_stroke_pat,
  812. "-tdegtk-outer-stroke-width", &outer_border,
  813. NULL);
  814. hide_border_sides (outer_border, hidden_side);
  815. if (tdegtk_gtk_border_is_zero (outer_border))
  816. goto end_draw_outer_stroke;
  817. apply_default_color (colors, outer_stroke_color);
  818. cairo_save (cr);
  819. cairo_translate (cr, x, y);
  820. /* create the path to fill */
  821. _gtk_rounded_box_init_rect (&border_box, 0, 0, width, height);
  822. _gtk_rounded_box_apply_border_radius (&border_box, engine, state, junction);
  823. padding_box = border_box;
  824. _gtk_rounded_box_shrink (&padding_box, outer_border->top,
  825. outer_border->right,
  826. outer_border->bottom,
  827. outer_border->left);
  828. cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
  829. if (outer_stroke_pat)
  830. {
  831. /* pattern */
  832. cairo_scale (cr, width, height);
  833. cairo_set_source (cr, outer_stroke_pat);
  834. cairo_scale (cr, 1.0 / width, 1.0 / height);
  835. _gtk_rounded_box_path (&border_box, cr);
  836. _gtk_rounded_box_path (&padding_box, cr);
  837. cairo_fill (cr);
  838. }
  839. else if (gdk_rgba_equal (colors[0], colors[1]) &&
  840. gdk_rgba_equal (colors[0], colors[2]) &&
  841. gdk_rgba_equal (colors[0], colors[3]))
  842. {
  843. /* one color */
  844. gdk_cairo_set_source_rgba (cr, colors[0]);
  845. _gtk_rounded_box_path (&border_box, cr);
  846. _gtk_rounded_box_path (&padding_box, cr);
  847. cairo_fill (cr);
  848. }
  849. else
  850. {
  851. /* different colors */
  852. for (i = 0; i < 4; i++)
  853. {
  854. if (hidden_side & current_side[i])
  855. continue;
  856. for (j = 0; j < 4; j++)
  857. {
  858. if (hidden_side & current_side[j])
  859. continue;
  860. if (i == j ||
  861. gdk_rgba_equal (colors[i], colors[j]))
  862. {
  863. /* we were already painted when i == j */
  864. if (i > j)
  865. break;
  866. if (j == 0)
  867. _gtk_rounded_box_path_top (&border_box, &padding_box, cr);
  868. else if (j == 1)
  869. _gtk_rounded_box_path_right (&border_box, &padding_box, cr);
  870. else if (j == 2)
  871. _gtk_rounded_box_path_bottom (&border_box, &padding_box, cr);
  872. else if (j == 3)
  873. _gtk_rounded_box_path_left (&border_box, &padding_box, cr);
  874. }
  875. }
  876. /* we were already painted when i == j */
  877. if (i > j)
  878. continue;
  879. gdk_cairo_set_source_rgba (cr, colors[i]);
  880. cairo_fill (cr);
  881. }
  882. }
  883. cairo_restore (cr);
  884. end_draw_outer_stroke:
  885. gtk_border_free (outer_border);
  886. if (outer_stroke_pat != NULL)
  887. cairo_pattern_destroy (outer_stroke_pat);
  888. gdk_rgba_free (outer_stroke_color);
  889. for (i = 0; i < 4; i++)
  890. gdk_rgba_free (colors[i]);
  891. }
  892. void
  893. tdegtk_cairo_draw_frame (GtkThemingEngine *engine,
  894. cairo_t *cr,
  895. gdouble x,
  896. gdouble y,
  897. gdouble width,
  898. gdouble height,
  899. guint hidden_side,
  900. GtkJunctionSides junction)
  901. {
  902. GtkBorder border;
  903. GtkBorder *outer_border;
  904. GtkStateFlags state;
  905. state = gtk_theming_engine_get_state (engine);
  906. gtk_theming_engine_get (engine, state,
  907. "-tdegtk-outer-stroke-width", &outer_border,
  908. NULL);
  909. gtk_theming_engine_get_border (engine, state, &border);
  910. hide_border_sides (&border, hidden_side);
  911. hide_border_sides (outer_border, hidden_side);
  912. if (!tdegtk_gtk_border_is_zero (outer_border))
  913. {
  914. /* first layer, outer stroke */
  915. draw_outer_stroke (engine, cr,
  916. x, y,
  917. width, height,
  918. hidden_side, junction);
  919. shrink_with_border (outer_border, &x, &y, &width, &height);
  920. }
  921. /* second layer, inner stroke */
  922. draw_inner_stroke (engine, cr,
  923. x + border.left, y + border.top,
  924. width - (border.left + border.right), height - (border.top + border.bottom),
  925. hidden_side, junction);
  926. /* third layer, border */
  927. draw_border (engine, cr,
  928. x, y,
  929. width, height,
  930. hidden_side, junction);
  931. gtk_border_free (outer_border);
  932. }
  933. gboolean
  934. tdegtk_cairo_draw_from_texture (GtkThemingEngine *engine,
  935. cairo_t *cr,
  936. gdouble x,
  937. gdouble y,
  938. gdouble width,
  939. gdouble height)
  940. {
  941. GtkStateFlags state;
  942. GValue value = { 0, };
  943. cairo_pattern_t *texture = NULL;
  944. cairo_surface_t *surface = NULL;
  945. gboolean retval = FALSE;
  946. state = gtk_theming_engine_get_state (engine);
  947. gtk_theming_engine_get_property (engine, "background-image", state, &value);
  948. if (!G_VALUE_HOLDS_BOXED (&value))
  949. return FALSE;
  950. texture = g_value_dup_boxed (&value);
  951. g_value_unset (&value);
  952. if (texture != NULL)
  953. cairo_pattern_get_surface (texture, &surface);
  954. if (surface != NULL)
  955. {
  956. cairo_save (cr);
  957. cairo_scale (cr, width / cairo_image_surface_get_width (surface),
  958. height / cairo_image_surface_get_height (surface));
  959. cairo_set_source_surface (cr, surface, x, y);
  960. cairo_paint (cr);
  961. cairo_restore (cr);
  962. retval = TRUE;
  963. }
  964. if (texture != NULL)
  965. cairo_pattern_destroy (texture);
  966. return retval;
  967. }
  968. void
  969. tdegtk_cairo_round_rect (cairo_t *cr,
  970. gdouble x,
  971. gdouble y,
  972. gdouble width,
  973. gdouble height,
  974. gint radius,
  975. guint sides,
  976. GtkJunctionSides junction)
  977. {
  978. radius = CLAMP (radius, 0, MIN (width / 2, height / 2));
  979. if (sides & SIDE_RIGHT)
  980. {
  981. if (radius == 0 ||
  982. (junction & GTK_JUNCTION_CORNER_TOPRIGHT))
  983. cairo_move_to (cr, x + width, y);
  984. else
  985. {
  986. cairo_new_sub_path (cr);
  987. cairo_arc (cr, x + width - radius, y + radius, radius, - G_PI / 4, 0);
  988. }
  989. if (radius == 0 ||
  990. (junction & GTK_JUNCTION_CORNER_BOTTOMRIGHT))
  991. cairo_line_to (cr, x + width, y + height);
  992. else
  993. cairo_arc (cr, x + width - radius, y + height - radius, radius, 0, G_PI / 4);
  994. }
  995. if (sides & SIDE_BOTTOM)
  996. {
  997. if (radius != 0 &&
  998. ! (junction & GTK_JUNCTION_CORNER_BOTTOMRIGHT))
  999. {
  1000. if ((sides & SIDE_RIGHT) == 0)
  1001. cairo_new_sub_path (cr);
  1002. cairo_arc (cr, x + width - radius, y + height - radius, radius, G_PI / 4, G_PI / 2);
  1003. }
  1004. else if ((sides & SIDE_RIGHT) == 0)
  1005. cairo_move_to (cr, x + width, y + height);
  1006. if (radius == 0 ||
  1007. (junction & GTK_JUNCTION_CORNER_BOTTOMLEFT))
  1008. cairo_line_to (cr, x, y + height);
  1009. else
  1010. cairo_arc (cr, x + radius, y + height - radius, radius, G_PI / 2, 3 * (G_PI / 4));
  1011. }
  1012. else
  1013. cairo_move_to (cr, x, y + height);
  1014. if (sides & SIDE_LEFT)
  1015. {
  1016. if (radius != 0 &&
  1017. ! (junction & GTK_JUNCTION_CORNER_BOTTOMLEFT))
  1018. {
  1019. if ((sides & SIDE_BOTTOM) == 0)
  1020. cairo_new_sub_path (cr);
  1021. cairo_arc (cr, x + radius, y + height - radius, radius, 3 * (G_PI / 4), G_PI);
  1022. }
  1023. else if ((sides & SIDE_BOTTOM) == 0)
  1024. cairo_move_to (cr, x, y + height);
  1025. if (radius == 0 ||
  1026. (junction & GTK_JUNCTION_CORNER_TOPLEFT))
  1027. cairo_line_to (cr, x, y);
  1028. else
  1029. cairo_arc (cr, x + radius, y + radius, radius, G_PI, G_PI + G_PI / 4);
  1030. }
  1031. if (sides & SIDE_TOP)
  1032. {
  1033. if (radius != 0 &&
  1034. ! (junction & GTK_JUNCTION_CORNER_TOPLEFT))
  1035. {
  1036. if ((sides & SIDE_LEFT) == 0)
  1037. cairo_new_sub_path (cr);
  1038. cairo_arc (cr, x + radius, y + radius, radius, 5 * (G_PI / 4), 3 * (G_PI / 2));
  1039. }
  1040. else if ((sides & SIDE_LEFT) == 0)
  1041. cairo_move_to (cr, x, y);
  1042. if (radius == 0 ||
  1043. (junction & GTK_JUNCTION_CORNER_TOPRIGHT))
  1044. cairo_line_to (cr, x + width, y);
  1045. else
  1046. cairo_arc (cr, x + width - radius, y + radius, radius, 3 * (G_PI / 2), - G_PI / 4);
  1047. }
  1048. }
  1049. void
  1050. tdegtk_cairo_round_rect_inner (cairo_t *cr,
  1051. gdouble x,
  1052. gdouble y,
  1053. gdouble width,
  1054. gdouble height,
  1055. gint radius,
  1056. guint sides,
  1057. GtkJunctionSides junction)
  1058. {
  1059. gdouble line_width;
  1060. line_width = cairo_get_line_width (cr);
  1061. /* center the rounded rectangle using line_width */
  1062. tdegtk_cairo_round_rect (cr, x + line_width / 2.0,
  1063. y + line_width / 2.0,
  1064. width - line_width,
  1065. height - line_width,
  1066. radius, sides, junction);
  1067. }
  1068. void
  1069. tdegtk_cairo_set_source_border (GtkThemingEngine *engine,
  1070. cairo_t *cr,
  1071. gdouble width,
  1072. gdouble height)
  1073. {
  1074. GdkRGBA border_color;
  1075. GtkBorderStyle border_style;
  1076. GtkStateFlags state;
  1077. cairo_pattern_t *border_pat;
  1078. state = gtk_theming_engine_get_state (engine);
  1079. gtk_theming_engine_get (engine, state,
  1080. "border-style", &border_style,
  1081. NULL);
  1082. gtk_theming_engine_get_border_color (engine, state, &border_color);
  1083. if (border_pat)
  1084. {
  1085. /* pattern */
  1086. cairo_scale (cr, width, height);
  1087. cairo_set_source (cr, border_pat);
  1088. cairo_scale (cr, 1.0 / width, 1.0 / height);
  1089. }
  1090. else
  1091. /* one color */
  1092. gdk_cairo_set_source_rgba (cr, &border_color);
  1093. if (border_pat != NULL)
  1094. cairo_pattern_destroy (border_pat);
  1095. }
  1096. void
  1097. tdegtk_cairo_set_source_inner_stroke (GtkThemingEngine *engine,
  1098. cairo_t *cr,
  1099. gdouble width,
  1100. gdouble height)
  1101. {
  1102. GdkRGBA *inner_stroke_color;
  1103. GtkStateFlags state;
  1104. cairo_pattern_t *inner_stroke_pat;
  1105. state = gtk_theming_engine_get_state (engine);
  1106. gtk_theming_engine_get (engine, state,
  1107. "-tdegtk-inner-stroke-color", &inner_stroke_color,
  1108. "-tdegtk-inner-stroke-gradient", &inner_stroke_pat,
  1109. NULL);
  1110. if (inner_stroke_pat)
  1111. {
  1112. /* pattern */
  1113. cairo_scale (cr, width, height);
  1114. cairo_set_source (cr, inner_stroke_pat);
  1115. cairo_scale (cr, 1.0 / width, 1.0 / height);
  1116. }
  1117. else
  1118. /* one color */
  1119. gdk_cairo_set_source_rgba (cr, inner_stroke_color);
  1120. if (inner_stroke_pat != NULL)
  1121. cairo_pattern_destroy (inner_stroke_pat);
  1122. gdk_rgba_free (inner_stroke_color);
  1123. }