KMPlayer – media player
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.

1692 lines
61KB

  1. /**
  2. This file belong to the KMPlayer project, a movie player plugin for Konqueror
  3. Copyright (C) 2007 Koos Vriezen <koos.vriezen@gmail.com>
  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. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with this library; if not, write to the Free Software
  14. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  15. **/
  16. #include <config.h>
  17. #include <stdlib.h>
  18. #include <math.h>
  19. #include <tqapplication.h>
  20. #include <tqwidgetstack.h>
  21. #include <tqslider.h>
  22. #include <tqcursor.h>
  23. #include <tqimage.h>
  24. #include <tqmap.h>
  25. #include <tdeactioncollection.h>
  26. #include <kstaticdeleter.h>
  27. #include <kstatusbar.h>
  28. #include <kstdaction.h>
  29. #include <tdeshortcut.h>
  30. #include <tdelocale.h>
  31. #include <kdebug.h>
  32. #include "kmplayerview.h"
  33. #include "kmplayercontrolpanel.h"
  34. #include "playlistview.h"
  35. #include "viewarea.h"
  36. #ifdef HAVE_CAIRO
  37. # include <cairo-xlib.h>
  38. # include <cairo-xlib-xrender.h>
  39. #endif
  40. #include "kmplayer_smil.h"
  41. #include "kmplayer_rp.h"
  42. using namespace KMPlayer;
  43. extern const char * normal_window_xpm[];
  44. extern const char * playlist_xpm[];
  45. //-------------------------------------------------------------------------
  46. namespace KMPlayer {
  47. typedef TQMap <TQString, ImageDataPtrW> ImageDataMap;
  48. static KStaticDeleter <ImageDataMap> imageCacheDeleter;
  49. static ImageDataMap * image_data_map;
  50. }
  51. ImageData::ImageData( const TQString & img) :
  52. image (0L),
  53. url (img) {
  54. //if (img.isEmpty ())
  55. // //kdDebug() << "New ImageData for " << this << endl;
  56. //else
  57. // //kdDebug() << "New ImageData for " << img << endl;
  58. }
  59. ImageData::~ImageData() {
  60. if (!url.isEmpty ())
  61. image_data_map->erase (url);
  62. delete image;
  63. }
  64. #ifdef HAVE_CAIRO
  65. static void copyImage (Surface *s, int w, int h, TQImage *img, cairo_surface_t *similar) {
  66. int iw = img->width ();
  67. int ih = img->height ();
  68. if (img->depth () < 24) {
  69. TQImage qi = img->convertDepth (32, 0);
  70. *img = qi;
  71. }
  72. cairo_surface_t *sf = cairo_image_surface_create_for_data (
  73. img->bits (),
  74. img->hasAlphaBuffer () ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24,
  75. iw, ih, img->bytesPerLine ());
  76. cairo_pattern_t *img_pat = cairo_pattern_create_for_surface (sf);
  77. cairo_pattern_set_extend (img_pat, CAIRO_EXTEND_NONE);
  78. if (w != iw && h != ih) {
  79. cairo_matrix_t mat;
  80. cairo_matrix_init_scale (&mat, 1.0 * iw/w, 1.0 * ih/h);
  81. cairo_pattern_set_matrix (img_pat, &mat);
  82. }
  83. if (!s->surface)
  84. s->surface = cairo_surface_create_similar (similar,
  85. img->hasAlphaBuffer () ?
  86. CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR, w, h);
  87. cairo_t *cr = cairo_create (s->surface);
  88. cairo_set_source (cr, img_pat);
  89. cairo_paint (cr);
  90. cairo_destroy (cr);
  91. cairo_pattern_destroy (img_pat);
  92. cairo_surface_destroy (sf);
  93. }
  94. #endif
  95. bool CachedImage::isEmpty () {
  96. return !data || !data->image;
  97. }
  98. void CachedImage::setUrl (const TQString & url) {
  99. if (url.isEmpty ()) {
  100. data = ImageDataPtr (new ImageData (url));
  101. } else {
  102. ImageDataMap::iterator i = image_data_map->find (url);
  103. if (i == image_data_map->end ()) {
  104. data = ImageDataPtr (new ImageData (url));
  105. image_data_map->insert (url, ImageDataPtrW (data));
  106. } else {
  107. ImageDataPtr safe = i.data ();
  108. data = safe;
  109. }
  110. }
  111. }
  112. //-------------------------------------------------------------------------
  113. namespace KMPlayer {
  114. class KMPLAYER_NO_EXPORT ViewSurface : public Surface {
  115. public:
  116. ViewSurface (ViewArea * widget);
  117. ViewSurface (ViewArea * widget, NodePtr owner, const SRect & rect);
  118. ~ViewSurface ();
  119. void clear () { m_first_child = 0L; }
  120. SurfacePtr createSurface (NodePtr owner, const SRect & rect);
  121. IRect toScreen (Single x, Single y, Single w, Single h);
  122. void resize (const SRect & rect);
  123. void repaint ();
  124. void repaint (const SRect &rect);
  125. void video ();
  126. NodePtrW current_video;
  127. ViewArea * view_widget;
  128. };
  129. } // namespace
  130. KDE_NO_CDTOR_EXPORT ViewSurface::ViewSurface (ViewArea * widget)
  131. : Surface (NULL, SRect (0, 0, widget->width (), widget->height ())),
  132. view_widget (widget)
  133. {}
  134. KDE_NO_CDTOR_EXPORT
  135. ViewSurface::ViewSurface (ViewArea * widget, NodePtr owner, const SRect & rect)
  136. : Surface (owner, rect), view_widget (widget) {}
  137. KDE_NO_CDTOR_EXPORT ViewSurface::~ViewSurface() {
  138. //kdDebug() << "~ViewSurface" << endl;
  139. }
  140. SurfacePtr ViewSurface::createSurface (NodePtr owner, const SRect & rect) {
  141. SurfacePtr surface = new ViewSurface (view_widget, owner, rect);
  142. appendChild (surface);
  143. return surface;
  144. }
  145. KDE_NO_EXPORT void ViewSurface::resize (const SRect &r) {
  146. bounds = r;
  147. #ifdef HAVE_CAIRO
  148. if (surface)
  149. cairo_xlib_surface_set_size (surface, (int)r.width(), (int)r.height ());
  150. #endif
  151. /*if (rect == nrect)
  152. ;//return;
  153. SRect pr = rect.unite (nrect); // for repaint
  154. rect = nrect;*/
  155. }
  156. KDE_NO_EXPORT IRect ViewSurface::toScreen (Single x, Single y, Single w, Single h) {
  157. Matrix matrix (0, 0, xscale, yscale);
  158. matrix.translate (bounds.x (), bounds.y ());
  159. for (SurfacePtr s = parentNode(); s; s = s->parentNode()) {
  160. matrix.transform(Matrix (0, 0, s->xscale, s->yscale));
  161. matrix.translate (s->bounds.x (), s->bounds.y ());
  162. }
  163. matrix.getXYWH (x, y, w, h);
  164. return IRect (x, y, w, h);
  165. }
  166. KDE_NO_EXPORT
  167. void ViewSurface::repaint (const SRect &r) {
  168. markDirty ();
  169. view_widget->scheduleRepaint (toScreen (r.x (), r.y (), r.width (), r.height ()));
  170. //kdDebug() << "Surface::repaint x:" << (int)x << " y:" << (int)y << " w:" << (int)w << " h:" << (int)h << endl;
  171. }
  172. KDE_NO_EXPORT
  173. void ViewSurface::repaint () {
  174. markDirty ();
  175. view_widget->scheduleRepaint (toScreen (0, 0, bounds.width (), bounds.height ()));
  176. }
  177. KDE_NO_EXPORT void ViewSurface::video () {
  178. view_widget->setAudioVideoNode (node);
  179. kdDebug() << "Surface::video:" << background_color << " " << (background_color & 0xff000000) << endl;
  180. xscale = yscale = 1; // either scale width/heigt or use bounds
  181. view_widget->setAudioVideoGeometry (toScreen (0, 0, bounds.width(), bounds.height ()),
  182. (background_color & 0xff000000 ? &background_color : 0));
  183. }
  184. //-------------------------------------------------------------------------
  185. #ifdef HAVE_CAIRO
  186. static cairo_surface_t * cairoCreateSurface (Window id, int w, int h) {
  187. Display * display = tqt_xdisplay ();
  188. return cairo_xlib_surface_create (display, id,
  189. DefaultVisual (display, DefaultScreen (display)), w, h);
  190. /*return cairo_xlib_surface_create_with_xrender_format (
  191. tqt_xdisplay (),
  192. id,
  193. DefaultScreenOfDisplay (tqt_xdisplay ()),
  194. XRenderFindVisualFormat (tqt_xdisplay (),
  195. DefaultVisual (tqt_xdisplay (),
  196. DefaultScreen (tqt_xdisplay ()))),
  197. w, h);*/
  198. }
  199. # define CAIRO_SET_SOURCE_RGB(cr,c) \
  200. cairo_set_source_rgb ((cr), \
  201. 1.0 * (((c) >> 16) & 0xff) / 255, \
  202. 1.0 * (((c) >> 8) & 0xff) / 255, \
  203. 1.0 * (((c)) & 0xff) / 255)
  204. class KMPLAYER_NO_EXPORT CairoPaintVisitor : public Visitor {
  205. IRect clip;
  206. cairo_surface_t * cairo_surface;
  207. Matrix matrix;
  208. // stack vars need for transitions
  209. SMIL::MediaType *cur_media;
  210. cairo_pattern_t * cur_pat;
  211. cairo_matrix_t cur_mat;
  212. float opacity;
  213. bool toplevel;
  214. void traverseRegion (SMIL::RegionBase * reg);
  215. void updateExternal (SMIL::MediaType *av, SurfacePtr s);
  216. void paint(SMIL::MediaType *, Surface *, int x, int y, const IRect &);
  217. public:
  218. cairo_t * cr;
  219. CairoPaintVisitor (cairo_surface_t * cs, Matrix m,
  220. const IRect & rect, TQColor c=TQColor(), bool toplevel=false);
  221. ~CairoPaintVisitor ();
  222. using Visitor::visit;
  223. void visit (Node * n);
  224. void visit (SMIL::Layout *);
  225. void visit (SMIL::Region *);
  226. void visit (SMIL::Transition *);
  227. void visit (SMIL::ImageMediaType *);
  228. void visit (SMIL::TextMediaType *);
  229. void visit (SMIL::Brush *);
  230. void visit (SMIL::RefMediaType *);
  231. void visit (SMIL::AVMediaType *);
  232. void visit (RP::Imfl *);
  233. void visit (RP::Fill *);
  234. void visit (RP::Fadein *);
  235. void visit (RP::Fadeout *);
  236. void visit (RP::Crossfade *);
  237. void visit (RP::Wipe *);
  238. void visit (RP::ViewChange *);
  239. };
  240. KDE_NO_CDTOR_EXPORT
  241. CairoPaintVisitor::CairoPaintVisitor (cairo_surface_t * cs, Matrix m,
  242. const IRect & rect, TQColor c, bool top)
  243. : clip (rect), cairo_surface (cs), matrix (m), toplevel (top) {
  244. cr = cairo_create (cs);
  245. if (toplevel) {
  246. cairo_rectangle (cr, rect.x, rect.y, rect.w, rect.h);
  247. cairo_clip (cr);
  248. //cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
  249. cairo_set_tolerance (cr, 0.5 );
  250. cairo_push_group (cr);
  251. cairo_set_source_rgb (cr,
  252. 1.0 * c.red () / 255, 1.0 * c.green () / 255, 1.0 * c.blue () / 255);
  253. cairo_rectangle (cr, rect.x, rect.y, rect.w, rect.h);
  254. cairo_fill (cr);
  255. } else {
  256. cairo_save (cr);
  257. cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
  258. cairo_rectangle (cr, rect.x, rect.y, rect.w, rect.h);
  259. cairo_fill (cr);
  260. cairo_restore (cr);
  261. }
  262. }
  263. KDE_NO_CDTOR_EXPORT CairoPaintVisitor::~CairoPaintVisitor () {
  264. if (toplevel) {
  265. cairo_pattern_t * pat = cairo_pop_group (cr);
  266. //cairo_pattern_set_extend (pat, CAIRO_EXTEND_NONE);
  267. cairo_set_source (cr, pat);
  268. cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h);
  269. cairo_fill (cr);
  270. cairo_pattern_destroy (pat);
  271. }
  272. cairo_destroy (cr);
  273. }
  274. KDE_NO_EXPORT void CairoPaintVisitor::visit (Node * n) {
  275. kdWarning() << "Paint called on " << n->nodeName() << endl;
  276. }
  277. KDE_NO_EXPORT void CairoPaintVisitor::traverseRegion (SMIL::RegionBase * reg) {
  278. // next visit listeners
  279. NodeRefListPtr nl = reg->listeners (mediatype_attached);
  280. if (nl) {
  281. for (NodeRefItemPtr c = nl->first(); c; c = c->nextSibling ())
  282. if (c->data)
  283. c->data->accept (this);
  284. }
  285. // finally visit children, accounting for z-order FIXME optimize
  286. NodeRefList sorted;
  287. for (NodePtr n = reg->firstChild (); n; n = n->nextSibling ()) {
  288. if (n->id != SMIL::id_node_region)
  289. continue;
  290. SMIL::Region * r = static_cast <SMIL::Region *> (n.ptr ());
  291. NodeRefItemPtr rn = sorted.first ();
  292. for (; rn; rn = rn->nextSibling ())
  293. if (r->z_order < convertNode <SMIL::Region> (rn->data)->z_order) {
  294. sorted.insertBefore (new NodeRefItem (n), rn);
  295. break;
  296. }
  297. if (!rn)
  298. sorted.append (new NodeRefItem (n));
  299. }
  300. for (NodeRefItemPtr r = sorted.first (); r; r = r->nextSibling ())
  301. r->data->accept (this);
  302. }
  303. KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::Layout * reg) {
  304. //kdDebug() << "Visit " << reg->nodeName() << endl;
  305. SMIL::RegionBase *rb = convertNode <SMIL::RegionBase> (reg->rootLayout);
  306. if (reg->surface () && rb) {
  307. //cairo_save (cr);
  308. Matrix m = matrix;
  309. SRect rect = reg->region_surface->bounds;
  310. Single x, y, w = rect.width(), h = rect.height();
  311. matrix.getXYWH (x, y, w, h);
  312. IRect clip_save = clip;
  313. clip = clip.intersect (IRect (x, y, w, h));
  314. rb->region_surface = reg->region_surface;
  315. rb->region_surface->background_color = rb->background_color;
  316. if (reg->region_surface->background_color & 0xff000000) {
  317. CAIRO_SET_SOURCE_RGB (cr, reg->region_surface->background_color);
  318. cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h);
  319. cairo_fill (cr);
  320. }
  321. //cairo_rectangle (cr, xoff, yoff, w, h);
  322. //cairo_clip (cr);
  323. matrix = Matrix (0, 0, reg->region_surface->xscale, reg->region_surface->yscale);
  324. matrix.transform (m);
  325. traverseRegion (reg);
  326. //cairo_restore (cr);
  327. matrix = m;
  328. clip = clip_save;
  329. rb->region_surface = 0L;
  330. }
  331. }
  332. KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::Region * reg) {
  333. Surface *s = reg->surface ();
  334. if (s) {
  335. SRect rect = s->bounds;
  336. Matrix m = matrix;
  337. Single x = rect.x(), y = rect.y(), w = rect.width(), h = rect.height();
  338. matrix.getXYWH (x, y, w, h);
  339. if (clip.intersect (IRect (x, y, w, h)).isEmpty ())
  340. return;
  341. matrix = Matrix (rect.x(), rect.y(), 1.0, 1.0);
  342. matrix.transform (m);
  343. IRect clip_save = clip;
  344. clip = clip.intersect (IRect (x, y, w, h));
  345. cairo_save (cr);
  346. if ((SMIL::RegionBase::ShowAlways == reg->show_background ||
  347. reg->m_AttachedMediaTypes->first ()) &&
  348. (s->background_color & 0xff000000 ||
  349. !reg->cached_img.isEmpty ())) {
  350. cairo_save (cr);
  351. if (s->background_color & 0xff000000) {
  352. CAIRO_SET_SOURCE_RGB (cr, s->background_color);
  353. cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h);
  354. cairo_fill (cr);
  355. }
  356. if (!reg->cached_img.isEmpty ()) {
  357. Single x1, y1;
  358. Single w = reg->cached_img.data->image->width ();
  359. Single h = reg->cached_img.data->image->height();
  360. matrix.getXYWH (x1, y1, w, h);
  361. if (!s->surface)
  362. copyImage (s, w, h, reg->cached_img.data->image, cairo_surface);
  363. cairo_pattern_t *pat = cairo_pattern_create_for_surface (s->surface);
  364. cairo_pattern_set_extend (pat, CAIRO_EXTEND_REPEAT);
  365. cairo_matrix_t mat;
  366. cairo_matrix_init_translate (&mat, (int) -x, (int) -y);
  367. cairo_pattern_set_matrix (pat, &mat);
  368. cairo_set_source (cr, pat);
  369. cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h);
  370. cairo_fill (cr);
  371. cairo_pattern_destroy (pat);
  372. }
  373. cairo_restore (cr);
  374. }
  375. traverseRegion (reg);
  376. cairo_restore (cr);
  377. matrix = m;
  378. clip = clip_save;
  379. }
  380. }
  381. #define CAIRO_SET_PATTERN_COND(cr,pat,mat) \
  382. if (pat) { \
  383. cairo_pattern_set_extend (cur_pat, CAIRO_EXTEND_NONE); \
  384. cairo_pattern_set_matrix (pat, &mat); \
  385. cairo_pattern_set_filter (pat, CAIRO_FILTER_FAST); \
  386. cairo_set_source (cr, pat); \
  387. }
  388. KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::Transition *trans) {
  389. float perc = trans->start_progress + (trans->end_progress - trans->start_progress)*cur_media->trans_step / cur_media->trans_steps;
  390. if (cur_media->trans_out_active)
  391. perc = 1.0 - perc;
  392. if (SMIL::Transition::Fade == trans->type) {
  393. CAIRO_SET_PATTERN_COND(cr, cur_pat, cur_mat)
  394. cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h);
  395. opacity = perc;
  396. } else if (SMIL::Transition::BarWipe == trans->type) {
  397. IRect rect;
  398. if (SMIL::Transition::SubTopToBottom == trans->sub_type) {
  399. if (SMIL::Transition::dir_reverse == trans->direction) {
  400. int dy = (int) ((1.0 - perc) * clip.h);
  401. rect = IRect (clip.x, clip.y + dy, clip.w, clip.h - dy);
  402. } else {
  403. rect = IRect (clip.x, clip.y, clip.w, (int) (perc * clip.h));
  404. }
  405. } else {
  406. if (SMIL::Transition::dir_reverse == trans->direction) {
  407. int dx = (int) ((1.0 - perc) * clip.w);
  408. rect = IRect (clip.x + dx, clip.y, clip.w - dx, clip.h);
  409. } else {
  410. rect = IRect (clip.x, clip.y, (int) (perc * clip.w), clip.h);
  411. }
  412. }
  413. cairo_rectangle (cr, rect.x, rect.y, rect.w, rect.h);
  414. CAIRO_SET_PATTERN_COND(cr, cur_pat, cur_mat)
  415. } else if (SMIL::Transition::PushWipe == trans->type) {
  416. int dx = 0, dy = 0;
  417. if (SMIL::Transition::SubFromTop == trans->sub_type)
  418. dy = -(int) ((1.0 - perc) * clip.h);
  419. else if (SMIL::Transition::SubFromRight == trans->sub_type)
  420. dx = (int) ((1.0 - perc) * clip.w);
  421. else if (SMIL::Transition::SubFromBottom == trans->sub_type)
  422. dy = (int) ((1.0 - perc) * clip.h);
  423. else //if (SMIL::Transition::SubFromLeft == trans->sub_type)
  424. dx = -(int) ((1.0 - perc) * clip.w);
  425. cairo_matrix_translate (&cur_mat, -dx, -dy);
  426. IRect rect = clip.intersect (IRect (clip.x + dx, clip.y + dy,
  427. clip.w - dx, clip.h - dy));
  428. cairo_rectangle (cr, rect.x, rect.y, rect.w, rect.h);
  429. CAIRO_SET_PATTERN_COND(cr, cur_pat, cur_mat)
  430. } else if (SMIL::Transition::IrisWipe == trans->type) {
  431. CAIRO_SET_PATTERN_COND(cr, cur_pat, cur_mat)
  432. if (SMIL::Transition::SubDiamond == trans->sub_type) {
  433. cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h);
  434. cairo_clip (cr);
  435. int dx = (int) (perc * clip.w);
  436. int dy = (int) (perc * clip.h);
  437. int mx = clip.x + clip.w/2;
  438. int my = clip.y + clip.h/2;
  439. cairo_new_path (cr);
  440. cairo_move_to (cr, mx, my - dy);
  441. cairo_line_to (cr, mx + dx, my);
  442. cairo_line_to (cr, mx, my + dy);
  443. cairo_line_to (cr, mx - dx, my);
  444. cairo_close_path (cr);
  445. } else { // SubRectangle
  446. int dx = (int) (0.5 * (1 - perc) * clip.w);
  447. int dy = (int) (0.5 * (1 - perc) * clip.h);
  448. cairo_rectangle (cr, clip.x + dx, clip.y + dy,
  449. clip.w - 2 * dx, clip.h -2 * dy);
  450. }
  451. } else if (SMIL::Transition::ClockWipe == trans->type) {
  452. cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h);
  453. cairo_clip (cr);
  454. int mx = clip.x + clip.w/2;
  455. int my = clip.y + clip.h/2;
  456. cairo_new_path (cr);
  457. cairo_move_to (cr, mx, my);
  458. float hw = 1.0 * clip.w/2;
  459. float hh = 1.0 * clip.h/2;
  460. float radius = sqrtf (hw * hw + hh * hh);
  461. float phi;
  462. switch (trans->sub_type) {
  463. case SMIL::Transition::SubClockwiseThree:
  464. phi = 0;
  465. break;
  466. case SMIL::Transition::SubClockwiseSix:
  467. phi = M_PI / 2;
  468. break;
  469. case SMIL::Transition::SubClockwiseNine:
  470. phi = M_PI;
  471. break;
  472. default: // Twelve
  473. phi = -M_PI / 2;
  474. break;
  475. }
  476. if (SMIL::Transition::dir_reverse == trans->direction)
  477. cairo_arc_negative (cr, mx, my, radius, phi, phi - 2 * M_PI * perc);
  478. else
  479. cairo_arc (cr, mx, my, radius, phi, phi + 2 * M_PI * perc);
  480. cairo_close_path (cr);
  481. CAIRO_SET_PATTERN_COND(cr, cur_pat, cur_mat)
  482. } else if (SMIL::Transition::BowTieWipe == trans->type) {
  483. cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h);
  484. cairo_clip (cr);
  485. int mx = clip.x + clip.w/2;
  486. int my = clip.y + clip.h/2;
  487. cairo_new_path (cr);
  488. cairo_move_to (cr, mx, my);
  489. float hw = 1.0 * clip.w/2;
  490. float hh = 1.0 * clip.h/2;
  491. float radius = sqrtf (hw * hw + hh * hh);
  492. float phi;
  493. switch (trans->sub_type) {
  494. case SMIL::Transition::SubHorizontal:
  495. phi = 0;
  496. break;
  497. default: // Vertical
  498. phi = -M_PI / 2;
  499. break;
  500. }
  501. float dphi = 0.5 * M_PI * perc;
  502. cairo_arc (cr, mx, my, radius, phi - dphi, phi + dphi);
  503. cairo_close_path (cr);
  504. cairo_new_sub_path (cr);
  505. cairo_move_to (cr, mx, my);
  506. if (SMIL::Transition::SubHorizontal == trans->sub_type)
  507. cairo_arc (cr, mx, my, radius, M_PI + phi - dphi, M_PI + phi +dphi);
  508. else
  509. cairo_arc (cr, mx, my, radius, -phi - dphi, -phi + dphi);
  510. cairo_close_path (cr);
  511. CAIRO_SET_PATTERN_COND(cr, cur_pat, cur_mat)
  512. } else if (SMIL::Transition::EllipseWipe == trans->type) {
  513. cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h);
  514. cairo_clip (cr);
  515. int mx = clip.x + clip.w/2;
  516. int my = clip.y + clip.h/2;
  517. float hw = (double) clip.w/2;
  518. float hh = (double) clip.h/2;
  519. float radius = sqrtf (hw * hw + hh * hh);
  520. cairo_save (cr);
  521. cairo_new_path (cr);
  522. cairo_translate (cr, (int) mx, (int) my);
  523. cairo_move_to (cr, - Single (radius), 0);
  524. if (SMIL::Transition::SubHorizontal == trans->sub_type)
  525. cairo_scale (cr, 1.0, 0.6);
  526. else if (SMIL::Transition::SubVertical == trans->sub_type)
  527. cairo_scale (cr, 0.6, 1.0);
  528. cairo_arc (cr, 0, 0, perc * radius, 0, 2 * M_PI);
  529. cairo_close_path (cr);
  530. cairo_restore (cr);
  531. CAIRO_SET_PATTERN_COND(cr, cur_pat, cur_mat)
  532. }
  533. }
  534. KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::RefMediaType *ref) {
  535. Surface *s = ref->surface ();
  536. if (s) {
  537. if (ref->external_tree)
  538. updateExternal (ref, s);
  539. else if (ref->needsVideoWidget ())
  540. s->video ();
  541. }
  542. }
  543. KDE_NO_EXPORT void CairoPaintVisitor::paint (SMIL::MediaType *mt, Surface *s,
  544. int x, int y, const IRect &rect) {
  545. cairo_save (cr);
  546. opacity = 1.0;
  547. cairo_matrix_init_translate (&cur_mat, -x, -y);
  548. cur_pat = cairo_pattern_create_for_surface (s->surface);
  549. if (mt->active_trans) {
  550. IRect clip_save = clip;
  551. clip = rect;
  552. cur_media = mt;
  553. mt->active_trans->accept (this);
  554. clip = clip_save;
  555. } else {
  556. cairo_pattern_set_extend (cur_pat, CAIRO_EXTEND_NONE);
  557. cairo_pattern_set_matrix (cur_pat, &cur_mat);
  558. cairo_pattern_set_filter (cur_pat, CAIRO_FILTER_FAST);
  559. cairo_set_source (cr, cur_pat);
  560. cairo_rectangle (cr, rect.x, rect.y, rect.w, rect.h);
  561. }
  562. opacity *= mt->opacity / 100.0;
  563. if (opacity < 0.99) {
  564. cairo_clip (cr);
  565. cairo_paint_with_alpha (cr, opacity);
  566. } else {
  567. cairo_fill (cr);
  568. }
  569. cairo_pattern_destroy (cur_pat);
  570. cairo_restore (cr);
  571. }
  572. KDE_NO_EXPORT
  573. void CairoPaintVisitor::updateExternal (SMIL::MediaType *av, SurfacePtr s) {
  574. SRect rect = s->bounds;
  575. Single x = rect.x ();
  576. Single y = rect.y ();
  577. Single w = rect.width();
  578. Single h = rect.height();
  579. matrix.getXYWH (x, y, w, h);
  580. IRect clip_rect = clip.intersect (IRect (x, y, w, h));
  581. if (!clip_rect.isValid ())
  582. return;
  583. if (!s->surface || s->dirty) {
  584. Matrix m = matrix;
  585. m.translate (-x, -y);
  586. IRect r (clip_rect.x - (int) x - 1, clip_rect.y - (int) y - 1,
  587. clip_rect.w + 3, clip_rect.h + 3);
  588. if (!s->surface) {
  589. s->surface = cairo_surface_create_similar (cairo_surface,
  590. CAIRO_CONTENT_COLOR_ALPHA, (int) w, (int) h);
  591. r = IRect (0, 0, w, h);
  592. }
  593. CairoPaintVisitor visitor (s->surface, m, r);
  594. av->external_tree->accept (&visitor);
  595. s->dirty = false;
  596. }
  597. paint (av, s.ptr (), x, y, clip_rect);
  598. }
  599. KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::AVMediaType *av) {
  600. Surface *s = av->surface ();
  601. if (s) {
  602. if (av->external_tree)
  603. updateExternal (av, s);
  604. else if (av->needsVideoWidget ())
  605. s->video ();
  606. }
  607. }
  608. KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::ImageMediaType * img) {
  609. //kdDebug() << "Visit " << img->nodeName() << " " << img->src << endl;
  610. Surface *s = img->surface ();
  611. if (!s)
  612. return;
  613. if (img->external_tree) {
  614. updateExternal (img, s);
  615. return;
  616. }
  617. ImageRuntime * ir = static_cast <ImageRuntime *> (img->runtime ());
  618. ImageData * id = ir->cached_img.data.ptr ();
  619. if (!id || !id->image || img->width <= 0 || img->height <= 0) {
  620. s->remove();
  621. return;
  622. }
  623. SRect rect = s->bounds;
  624. Single x = rect.x ();
  625. Single y = rect.y ();
  626. Single w = rect.width();
  627. Single h = rect.height();
  628. matrix.getXYWH (x, y, w, h);
  629. IRect clip_rect = clip.intersect (IRect (x, y, w, h));
  630. if (clip_rect.isEmpty ())
  631. return;
  632. if (!s->surface || s->dirty)
  633. copyImage (s, w, h, id->image, cairo_surface);
  634. paint (img, s, x, y, clip_rect);
  635. s->dirty = false;
  636. }
  637. KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::TextMediaType * txt) {
  638. TextRuntime * td = static_cast <TextRuntime *> (txt->runtime ());
  639. Surface *s = txt->surface ();
  640. //kdDebug() << "Visit " << txt->nodeName() << " " << td->text << endl;
  641. if (!s)
  642. return;
  643. SRect rect = s->bounds;
  644. Single x = rect.x (), y = rect.y(), w = rect.width(), h = rect.height();
  645. matrix.getXYWH (x, y, w, h);
  646. if (!s->surface) {
  647. //kdDebug() << "new txt surface " << td->text << endl;
  648. /* TQTextEdit * edit = new TQTextEdit;
  649. edit->setReadOnly (true);
  650. edit->setHScrollBarMode (TQScrollView::AlwaysOff);
  651. edit->setVScrollBarMode (TQScrollView::AlwaysOff);
  652. edit->setFrameShape (TQFrame::NoFrame);
  653. edit->setFrameShadow (TQFrame::Plain);
  654. edit->setGeometry (0, 0, w, h);
  655. if (edit->length () == 0)
  656. edit->setText (text);
  657. if (w0 > 0)
  658. font.setPointSize (int (1.0 * w * font_size / w0));
  659. edit->setFont (font);
  660. TQRect rect = p.clipRegion (TQPainter::CoordPainter).boundingRect ();
  661. rect = rect.intersect (TQRect (xoff, yoff, w, h));
  662. TQPixmap pix = TQPixmap::grabWidget (edit, rect.x () - (int) xoff,
  663. rect.y () - (int) yoff, rect.width (), rect.height ());*/
  664. float scale = 1.0 * w / rect.width (); // TODO: make an image
  665. cairo_set_font_size (cr, scale * td->font_size);
  666. cairo_font_extents_t txt_fnt;
  667. cairo_font_extents (cr, &txt_fnt);
  668. TQString str = td->text;
  669. struct Line {
  670. Line (const TQString & ln) : txt (ln), next(0) {}
  671. TQString txt;
  672. cairo_text_extents_t txt_ext;
  673. Single xoff;
  674. Line * next;
  675. } *lines = 0, *last_line = 0;
  676. Single y1 = y;
  677. Single max_width;
  678. int line_count = 0;
  679. Single min_xoff = w;
  680. while (!str.isEmpty ()) {
  681. int len = str.find (TQChar ('\n'));
  682. bool skip_cr = false;
  683. if (len > 1 && str[len-1] == TQChar ('\r')) {
  684. --len;
  685. skip_cr = true;
  686. }
  687. TQString para = len > -1 ? str.left (len) : str;
  688. Line * line = new Line (para);
  689. ++line_count;
  690. if (!lines)
  691. lines = line;
  692. else
  693. last_line->next = line;
  694. last_line = line;
  695. int ppos = 0;
  696. while (true) {
  697. cairo_text_extents (cr, line->txt.utf8 ().data (), &line->txt_ext);
  698. float frag = line->txt_ext.width > 0.1
  699. ? w / line->txt_ext.width : 1.1;
  700. if (frag < 1.0) {
  701. int br_pos = int (line->txt.length () * frag); //educated guess
  702. while (br_pos > 0) {
  703. line->txt.truncate (br_pos);
  704. br_pos = line->txt.findRev (TQChar (' '));
  705. if (br_pos < 1)
  706. break;
  707. line->txt.truncate (br_pos);
  708. cairo_text_extents (cr, line->txt.utf8 ().data (), &line->txt_ext);
  709. if (line->txt_ext.width < (double)w)
  710. break;
  711. }
  712. }
  713. if (line->txt_ext.width > (double)max_width)
  714. max_width = line->txt_ext.width;
  715. if (td->halign == TextRuntime::align_center)
  716. line->xoff = (w - Single (line->txt_ext.width)) / 2;
  717. else if (td->halign == TextRuntime::align_right)
  718. line->xoff = w - Single (line->txt_ext.width);
  719. if (line->xoff < min_xoff)
  720. min_xoff = line->xoff;
  721. y1 += Single (txt_fnt.height);
  722. ppos += line->txt.length () + 1;
  723. if (ppos >= para.length ())
  724. break;
  725. line->next = new Line (para.mid (ppos));
  726. ++line_count;
  727. line = line->next;
  728. last_line = line;
  729. }
  730. if (len < 0)
  731. break;
  732. str = str.mid (len + (skip_cr ? 2 : 1));
  733. }
  734. // new coord in screen space
  735. x += min_xoff;
  736. w = (double)max_width + txt_fnt.max_x_advance / 2;
  737. h = y1 - y /*txt_fnt.height + txt_fnt.descent*/;
  738. s->surface = cairo_surface_create_similar (cairo_surface,
  739. CAIRO_CONTENT_COLOR, (int) w, (int) h);
  740. cairo_t * cr_txt = cairo_create (s->surface);
  741. cairo_set_font_size (cr_txt, scale * td->font_size);
  742. if (td->bg_opacity) { // TODO real alpha
  743. CAIRO_SET_SOURCE_RGB (cr_txt, td->background_color);
  744. cairo_paint (cr_txt);
  745. }
  746. CAIRO_SET_SOURCE_RGB (cr_txt, td->font_color);
  747. y1 = 0;
  748. while (lines) {
  749. Line * line = lines;
  750. line->xoff += Single (txt_fnt.max_x_advance / 4);
  751. cairo_move_to (cr_txt, line->xoff - min_xoff, y1 + Single (txt_fnt.ascent));
  752. cairo_show_text (cr_txt, line->txt.utf8 ().data ());
  753. y1 += Single (txt_fnt.height);
  754. lines = lines->next;
  755. delete line;
  756. }
  757. //cairo_stroke (cr);
  758. cairo_destroy (cr_txt);
  759. // update bounds rect
  760. Single sx = x, sy = y, sw = w, sh = h;
  761. matrix.invXYWH (sx, sy, sw, sh);
  762. txt->width = sw;
  763. txt->height = sh;
  764. s->bounds = txt->calculateBounds ();
  765. // update coord. for painting below
  766. x = s->bounds.x ();
  767. y = s->bounds.y();
  768. w = s->bounds.width();
  769. h = s->bounds.height();
  770. matrix.getXYWH (x, y, w, h);
  771. }
  772. IRect clip_rect = clip.intersect (IRect (x, y, w, h));
  773. if (!clip_rect.isEmpty ())
  774. paint (txt, s, x, y, clip_rect);
  775. s->dirty = false;
  776. }
  777. KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::Brush * brush) {
  778. //kdDebug() << "Visit " << brush->nodeName() << endl;
  779. Surface *s = brush->surface ();
  780. if (s) {
  781. cairo_save (cr);
  782. opacity = 1.0;
  783. SRect rect = s->bounds;
  784. Single x, y, w = rect.width(), h = rect.height();
  785. matrix.getXYWH (x, y, w, h);
  786. unsigned int color = TQColor (brush->param ("color")).rgb ();
  787. if (brush->active_trans) {
  788. cur_media = brush;
  789. cur_pat = NULL;
  790. brush->active_trans->accept (this);
  791. } else {
  792. cairo_rectangle (cr, (int) x, (int) y, (int) w, (int) h);
  793. }
  794. opacity *= brush->opacity / 100.0;
  795. if (opacity < 0.99)
  796. cairo_set_source_rgba (cr,
  797. 1.0 * ((color >> 16) & 0xff) / 255,
  798. 1.0 * ((color >> 8) & 0xff) / 255,
  799. 1.0 * (color & 0xff) / 255,
  800. opacity);
  801. else
  802. CAIRO_SET_SOURCE_RGB (cr, color);
  803. cairo_fill (cr);
  804. s->dirty = false;
  805. cairo_restore (cr);
  806. }
  807. }
  808. KDE_NO_EXPORT void CairoPaintVisitor::visit (RP::Imfl * imfl) {
  809. if (imfl->surface ()) {
  810. cairo_save (cr);
  811. Matrix m = matrix;
  812. Single x, y;
  813. Single w = imfl->rp_surface->bounds.width();
  814. Single h = imfl->rp_surface->bounds.height();
  815. matrix.getXYWH (x, y, w, h);
  816. cairo_rectangle (cr, x, y, w, h);
  817. //cairo_clip (cr);
  818. cairo_translate (cr, x, y);
  819. cairo_scale (cr, w/imfl->width, h/imfl->height);
  820. if (imfl->needs_scene_img)
  821. cairo_push_group (cr);
  822. for (NodePtr n = imfl->firstChild (); n; n = n->nextSibling ())
  823. if (n->state >= Node::state_began &&
  824. n->state < Node::state_deactivated) {
  825. RP::TimingsBase * tb = convertNode<RP::TimingsBase>(n);
  826. switch (n->id) {
  827. case RP::id_node_viewchange:
  828. if (!(int)tb->srcw)
  829. tb->srcw = imfl->width;
  830. if (!(int)tb->srch)
  831. tb->srch = imfl->height;
  832. // fall through
  833. case RP::id_node_crossfade:
  834. case RP::id_node_fadein:
  835. case RP::id_node_fadeout:
  836. case RP::id_node_fill:
  837. case RP::id_node_wipe:
  838. if (!(int)tb->w)
  839. tb->w = imfl->width;
  840. if (!(int)tb->h)
  841. tb->h = imfl->height;
  842. n->accept (this);
  843. break;
  844. }
  845. }
  846. if (imfl->needs_scene_img) {
  847. cairo_pattern_t * pat = cairo_pop_group (cr);
  848. cairo_pattern_set_extend (pat, CAIRO_EXTEND_NONE);
  849. cairo_set_source (cr, pat);
  850. cairo_paint (cr);
  851. cairo_pattern_destroy (pat);
  852. }
  853. cairo_restore (cr);
  854. matrix = m;
  855. }
  856. }
  857. KDE_NO_EXPORT void CairoPaintVisitor::visit (RP::Fill * fi) {
  858. //kdDebug() << "Visit " << fi->nodeName() << endl;
  859. CAIRO_SET_SOURCE_RGB (cr, fi->color);
  860. if ((int)fi->w && (int)fi->h) {
  861. cairo_rectangle (cr, fi->x, fi->y, fi->w, fi->h);
  862. cairo_fill (cr);
  863. }
  864. }
  865. KDE_NO_EXPORT void CairoPaintVisitor::visit (RP::Fadein * fi) {
  866. //kdDebug() << "Visit " << fi->nodeName() << endl;
  867. if (fi->target && fi->target->id == RP::id_node_image) {
  868. RP::Image *img = convertNode <RP::Image> (fi->target);
  869. if (img->surface ()) {
  870. Single sx = fi->srcx, sy = fi->srcy, sw = fi->srcw, sh = fi->srch;
  871. if (!(int)sw)
  872. sw = img->width;
  873. if (!(int)sh)
  874. sh = img->height;
  875. if ((int)fi->w && (int)fi->h && (int)sw && (int)sh) {
  876. if (!img->img_surface->surface)
  877. copyImage (img->img_surface, img->width, img->height, img->cached_img.data->image, cairo_surface);
  878. cairo_matrix_t matrix;
  879. cairo_matrix_init_identity (&matrix);
  880. float scalex = 1.0 * sw / fi->w;
  881. float scaley = 1.0 * sh / fi->h;
  882. cairo_matrix_scale (&matrix, scalex, scaley);
  883. cairo_matrix_translate (&matrix,
  884. 1.0*sx/scalex - (double)fi->x,
  885. 1.0*sy/scaley - (double)fi->y);
  886. cairo_save (cr);
  887. cairo_rectangle (cr, fi->x, fi->y, fi->w, fi->h);
  888. cairo_pattern_t *pat = cairo_pattern_create_for_surface (img->img_surface->surface);
  889. cairo_pattern_set_extend (pat, CAIRO_EXTEND_NONE);
  890. cairo_pattern_set_matrix (pat, &matrix);
  891. cairo_set_source (cr, pat);
  892. cairo_clip (cr);
  893. cairo_paint_with_alpha (cr, 1.0 * fi->progress / 100);
  894. cairo_restore (cr);
  895. cairo_pattern_destroy (pat);
  896. }
  897. }
  898. }
  899. }
  900. KDE_NO_EXPORT void CairoPaintVisitor::visit (RP::Fadeout * fo) {
  901. //kdDebug() << "Visit " << fo->nodeName() << endl;
  902. if (fo->progress > 0) {
  903. CAIRO_SET_SOURCE_RGB (cr, fo->to_color);
  904. if ((int)fo->w && (int)fo->h) {
  905. cairo_save (cr);
  906. cairo_rectangle (cr, fo->x, fo->y, fo->w, fo->h);
  907. cairo_clip (cr);
  908. cairo_paint_with_alpha (cr, 1.0 * fo->progress / 100);
  909. cairo_restore (cr);
  910. }
  911. }
  912. }
  913. KDE_NO_EXPORT void CairoPaintVisitor::visit (RP::Crossfade * cf) {
  914. //kdDebug() << "Visit " << cf->nodeName() << endl;
  915. if (cf->target && cf->target->id == RP::id_node_image) {
  916. RP::Image *img = convertNode <RP::Image> (cf->target);
  917. if (img->surface ()) {
  918. Single sx = cf->srcx, sy = cf->srcy, sw = cf->srcw, sh = cf->srch;
  919. if (!(int)sw)
  920. sw = img->width;
  921. if (!(int)sh)
  922. sh = img->height;
  923. if ((int)cf->w && (int)cf->h && (int)sw && (int)sh) {
  924. if (!img->img_surface->surface)
  925. copyImage (img->img_surface, img->width, img->height, img->cached_img.data->image, cairo_surface);
  926. cairo_save (cr);
  927. cairo_matrix_t matrix;
  928. cairo_matrix_init_identity (&matrix);
  929. float scalex = 1.0 * sw / cf->w;
  930. float scaley = 1.0 * sh / cf->h;
  931. cairo_matrix_scale (&matrix, scalex, scaley);
  932. cairo_matrix_translate (&matrix,
  933. 1.0*sx/scalex - (double)cf->x,
  934. 1.0*sy/scaley - (double)cf->y);
  935. cairo_rectangle (cr, cf->x, cf->y, cf->w, cf->h);
  936. cairo_pattern_t *pat = cairo_pattern_create_for_surface (img->img_surface->surface);
  937. cairo_pattern_set_extend (pat, CAIRO_EXTEND_NONE);
  938. cairo_pattern_set_matrix (pat, &matrix);
  939. cairo_set_source (cr, pat);
  940. cairo_clip (cr);
  941. cairo_paint_with_alpha (cr, 1.0 * cf->progress / 100);
  942. cairo_restore (cr);
  943. cairo_pattern_destroy (pat);
  944. }
  945. }
  946. }
  947. }
  948. KDE_NO_EXPORT void CairoPaintVisitor::visit (RP::Wipe * wipe) {
  949. //kdDebug() << "Visit " << wipe->nodeName() << endl;
  950. if (wipe->target && wipe->target->id == RP::id_node_image) {
  951. RP::Image *img = convertNode <RP::Image> (wipe->target);
  952. if (img->surface ()) {
  953. Single x = wipe->x, y = wipe->y;
  954. Single tx = x, ty = y;
  955. Single w = wipe->w, h = wipe->h;
  956. Single sx = wipe->srcx, sy = wipe->srcy, sw = wipe->srcw, sh = wipe->srch;
  957. if (!(int)sw)
  958. sw = img->width;
  959. if (!(int)sh)
  960. sh = img->height;
  961. if (wipe->direction == RP::Wipe::dir_right) {
  962. Single dx = w * 1.0 * wipe->progress / 100;
  963. tx = x -w + dx;
  964. w = dx;
  965. } else if (wipe->direction == RP::Wipe::dir_left) {
  966. Single dx = w * 1.0 * wipe->progress / 100;
  967. tx = x + w - dx;
  968. x = tx;
  969. w = dx;
  970. } else if (wipe->direction == RP::Wipe::dir_down) {
  971. Single dy = h * 1.0 * wipe->progress / 100;
  972. ty = y - h + dy;
  973. h = dy;
  974. } else if (wipe->direction == RP::Wipe::dir_up) {
  975. Single dy = h * 1.0 * wipe->progress / 100;
  976. ty = y + h - dy;
  977. y = ty;
  978. h = dy;
  979. }
  980. if ((int)w && (int)h) {
  981. if (!img->img_surface->surface)
  982. copyImage (img->img_surface, img->width, img->height, img->cached_img.data->image, cairo_surface);
  983. cairo_matrix_t matrix;
  984. cairo_matrix_init_identity (&matrix);
  985. float scalex = 1.0 * sw / wipe->w;
  986. float scaley = 1.0 * sh / wipe->h;
  987. cairo_matrix_scale (&matrix, scalex, scaley);
  988. cairo_matrix_translate (&matrix,
  989. 1.0*sx/scalex - (double)tx,
  990. 1.0*sy/scaley - (double)ty);
  991. cairo_pattern_t *pat = cairo_pattern_create_for_surface (img->img_surface->surface);
  992. cairo_pattern_set_extend (pat, CAIRO_EXTEND_NONE);
  993. cairo_pattern_set_matrix (pat, &matrix);
  994. cairo_set_source (cr, pat);
  995. cairo_rectangle (cr, x, y, w, h);
  996. cairo_fill (cr);
  997. cairo_pattern_destroy (pat);
  998. }
  999. }
  1000. }
  1001. }
  1002. KDE_NO_EXPORT void CairoPaintVisitor::visit (RP::ViewChange * vc) {
  1003. //kdDebug() << "Visit " << vc->nodeName() << endl;
  1004. if (vc->unfinished () || vc->progress < 100) {
  1005. cairo_pattern_t * pat = cairo_pop_group (cr); // from imfl
  1006. cairo_pattern_set_extend (pat, CAIRO_EXTEND_NONE);
  1007. cairo_push_group (cr);
  1008. cairo_save (cr);
  1009. cairo_set_source (cr, pat);
  1010. cairo_paint (cr);
  1011. if ((int)vc->w && (int)vc->h && (int)vc->srcw && (int)vc->srch) {
  1012. cairo_matrix_t matrix;
  1013. cairo_matrix_init_identity (&matrix);
  1014. float scalex = 1.0 * vc->srcw / vc->w;
  1015. float scaley = 1.0 * vc->srch / vc->h;
  1016. cairo_matrix_scale (&matrix, scalex, scaley);
  1017. cairo_matrix_translate (&matrix,
  1018. 1.0*vc->srcx/scalex - (double)vc->x,
  1019. 1.0*vc->srcy/scaley - (double)vc->y);
  1020. cairo_pattern_set_matrix (pat, &matrix);
  1021. cairo_set_source (cr, pat);
  1022. cairo_rectangle (cr, vc->x, vc->y, vc->w, vc->h);
  1023. cairo_fill (cr);
  1024. }
  1025. cairo_pattern_destroy (pat);
  1026. cairo_restore (cr);
  1027. }
  1028. }
  1029. #endif
  1030. //-----------------------------------------------------------------------------
  1031. namespace KMPlayer {
  1032. class KMPLAYER_NO_EXPORT MouseVisitor : public Visitor {
  1033. Matrix matrix;
  1034. NodePtr node;
  1035. unsigned int event;
  1036. int x, y;
  1037. bool handled;
  1038. bool bubble_up;
  1039. public:
  1040. MouseVisitor (unsigned int evt, int x, int y);
  1041. KDE_NO_CDTOR_EXPORT ~MouseVisitor () {}
  1042. using Visitor::visit;
  1043. void visit (Node * n);
  1044. void visit (SMIL::Layout *);
  1045. void visit (SMIL::Region *);
  1046. void visit (SMIL::TimedMrl * n);
  1047. void visit (SMIL::MediaType * n);
  1048. void visit (SMIL::Anchor *);
  1049. void visit (SMIL::Area *);
  1050. TQCursor cursor;
  1051. };
  1052. } // namespace
  1053. KDE_NO_CDTOR_EXPORT
  1054. MouseVisitor::MouseVisitor (unsigned int evt, int a, int b)
  1055. : event (evt), x (a), y (b), handled (false), bubble_up (false) {
  1056. }
  1057. KDE_NO_EXPORT void MouseVisitor::visit (Node * n) {
  1058. kdDebug () << "Mouse event ignored for " << n->nodeName () << endl;
  1059. }
  1060. KDE_NO_EXPORT void MouseVisitor::visit (SMIL::Layout * layout) {
  1061. if (layout->surface ()) {
  1062. Matrix m = matrix;
  1063. SRect rect = layout->region_surface->bounds;
  1064. matrix = Matrix (rect.x(), rect.y(),
  1065. layout->region_surface->xscale, layout->region_surface->yscale);
  1066. matrix.transform (m);
  1067. NodePtr node_save = node;
  1068. node = layout;
  1069. for (NodePtr r = layout->firstChild (); r; r = r->nextSibling ()) {
  1070. if (r->id == SMIL::id_node_region)
  1071. r->accept (this);
  1072. if (!node->active ())
  1073. break;
  1074. }
  1075. node = node_save;
  1076. matrix = m;
  1077. }
  1078. }
  1079. KDE_NO_EXPORT void MouseVisitor::visit (SMIL::Region * region) {
  1080. if (region->surface ()) {
  1081. SRect rect = region->region_surface->bounds;
  1082. Single rx = rect.x(), ry = rect.y(), rw = rect.width(), rh = rect.height();
  1083. matrix.getXYWH (rx, ry, rw, rh);
  1084. handled = false;
  1085. bool inside = x > rx && x < rx+rw && y > ry && y< ry+rh;
  1086. if (!inside && (event == event_pointer_clicked || !region->has_mouse))
  1087. return;
  1088. Matrix m = matrix;
  1089. matrix = Matrix (rect.x(), rect.y(), 1.0, 1.0);
  1090. matrix.transform (m);
  1091. bubble_up = false;
  1092. bool child_handled = false;
  1093. if (inside)
  1094. for (NodePtr r = region->firstChild (); r; r = r->nextSibling ()) {
  1095. r->accept (this);
  1096. child_handled |= handled;
  1097. if (!node->active ())
  1098. break;
  1099. }
  1100. child_handled &= !bubble_up;
  1101. bubble_up = false;
  1102. int saved_event = event;
  1103. if (node->active ()) {
  1104. bool propagate_listeners = !child_handled;
  1105. if (event == event_pointer_moved) {
  1106. propagate_listeners = true; // always pass move events
  1107. if (region->has_mouse && (!inside || child_handled)) {
  1108. region->has_mouse = false;
  1109. event = event_outbounds;
  1110. } else if (inside && !child_handled && !region->has_mouse) {
  1111. region->has_mouse = true;
  1112. event = event_inbounds;
  1113. }
  1114. }// else // event_pointer_clicked
  1115. if (propagate_listeners) {
  1116. NodeRefListPtr nl = region->listeners (
  1117. event == event_pointer_moved ? mediatype_attached : event);
  1118. if (nl) {
  1119. for (NodeRefItemPtr c = nl->first(); c; c = c->nextSibling ()) {
  1120. if (c->data)
  1121. c->data->accept (this);
  1122. if (!node->active ())
  1123. break;
  1124. }
  1125. }
  1126. }
  1127. }
  1128. event = saved_event;
  1129. handled = inside;
  1130. matrix = m;
  1131. }
  1132. }
  1133. static void followLink (SMIL::LinkingBase * link) {
  1134. kdDebug() << "link to " << link->href << " clicked" << endl;
  1135. NodePtr n = link;
  1136. if (link->href.startsWith ("#")) {
  1137. SMIL::Smil * s = SMIL::Smil::findSmilNode (link);
  1138. if (s)
  1139. s->jump (link->href.mid (1));
  1140. else
  1141. kdError() << "In document jumps smil not found" << endl;
  1142. } else
  1143. for (NodePtr p = link->parentNode (); p; p = p->parentNode ()) {
  1144. if (n->mrl () && n->mrl ()->opener == p) {
  1145. p->setState (Node::state_deferred);
  1146. p->mrl ()->setParam (StringPool::attr_src, link->href, 0L);
  1147. p->activate ();
  1148. break;
  1149. }
  1150. n = p;
  1151. }
  1152. }
  1153. KDE_NO_EXPORT void MouseVisitor::visit (SMIL::Anchor * anchor) {
  1154. if (event == event_pointer_moved)
  1155. cursor.setShape (Qt::PointingHandCursor);
  1156. else if (event == event_pointer_clicked)
  1157. followLink (anchor);
  1158. }
  1159. KDE_NO_EXPORT void MouseVisitor::visit (SMIL::Area * area) {
  1160. NodePtr n = area->parentNode ();
  1161. if (n->id >= SMIL::id_node_first_mediatype &&
  1162. n->id < SMIL::id_node_last_mediatype) {
  1163. SMIL::MediaType * mt = convertNode <SMIL::MediaType> (n);
  1164. Surface *s = mt->surface ();
  1165. if (s) {
  1166. SRect rect = s->bounds;
  1167. Single x1 = rect.x (), x2 = rect.y ();
  1168. Single w = rect.width (), h = rect.height ();
  1169. matrix.getXYWH (x1, x2, w, h);
  1170. if (area->nr_coords > 1) {
  1171. Single left = area->coords[0].size (rect.width ());
  1172. Single top = area->coords[1].size (rect.height ());
  1173. matrix.getXY (left, top);
  1174. if (x < left || x > left + w || y < top || y > top + h)
  1175. return;
  1176. if (area->nr_coords > 3) {
  1177. Single right = area->coords[2].size (rect.width ());
  1178. Single bottom = area->coords[3].size (rect.height ());
  1179. matrix.getXY (right, bottom);
  1180. if (x > right || y > bottom)
  1181. return;
  1182. }
  1183. }
  1184. if (event == event_pointer_moved)
  1185. cursor.setShape (Qt::PointingHandCursor);
  1186. else {
  1187. NodeRefListPtr nl = area->listeners (event);
  1188. if (nl)
  1189. for (NodeRefItemPtr c = nl->first(); c; c = c->nextSibling ()) {
  1190. if (c->data)
  1191. c->data->accept (this);
  1192. if (!node->active ())
  1193. return;
  1194. }
  1195. if (event == event_pointer_clicked && !area->href.isEmpty ())
  1196. followLink (area);
  1197. }
  1198. }
  1199. }
  1200. }
  1201. KDE_NO_EXPORT void MouseVisitor::visit (SMIL::TimedMrl * timedmrl) {
  1202. timedmrl->runtime ()->processEvent (event);
  1203. }
  1204. KDE_NO_EXPORT void MouseVisitor::visit (SMIL::MediaType * mediatype) {
  1205. if (mediatype->sensitivity == SMIL::MediaType::sens_transparent) {
  1206. bubble_up = true;
  1207. return;
  1208. }
  1209. Surface *s = mediatype->surface ();
  1210. if (!s)
  1211. return;
  1212. if (s->node && s->node.ptr () != mediatype) {
  1213. s->node->accept (this);
  1214. return;
  1215. }
  1216. SRect rect = s->bounds;
  1217. Single rx = rect.x(), ry = rect.y(), rw = rect.width(), rh = rect.height();
  1218. matrix.getXYWH (rx, ry, rw, rh);
  1219. bool inside = x > rx && x < rx+rw && y > ry && y< ry+rh;
  1220. if (!inside && event == event_pointer_clicked)
  1221. return; // FIXME, also in/outbounds are bounds related
  1222. NodeRefListPtr nl = mediatype->listeners (
  1223. event == event_pointer_moved ? mediatype_attached : event);
  1224. if (nl)
  1225. for (NodeRefItemPtr c = nl->first(); c; c = c->nextSibling ()) {
  1226. if (c->data)
  1227. c->data->accept (this);
  1228. if (!node->active ())
  1229. return;
  1230. }
  1231. if (event != event_pointer_moved)
  1232. visit (static_cast <SMIL::TimedMrl *> (mediatype));
  1233. if (event != event_inbounds && event != event_outbounds) {
  1234. SMIL::RegionBase *r=convertNode<SMIL::RegionBase>(mediatype->region_node);
  1235. if (r && r->surface () &&
  1236. r->id != SMIL::id_node_smil &&
  1237. r->region_surface->node && r != r->region_surface->node.ptr ())
  1238. return r->region_surface->node->accept (this);
  1239. }
  1240. }
  1241. //-----------------------------------------------------------------------------
  1242. KDE_NO_CDTOR_EXPORT ViewArea::ViewArea (TQWidget * parent, View * view)
  1243. : TQWidget (parent, "kde_kmplayer_viewarea", WResizeNoErase | WRepaintNoErase),
  1244. m_parent (parent),
  1245. m_view (view),
  1246. m_collection (new TDEActionCollection (this)),
  1247. surface (new ViewSurface (this)),
  1248. m_mouse_invisible_timer (0),
  1249. m_repaint_timer (0),
  1250. m_fullscreen_scale (100),
  1251. scale_lbl_id (-1),
  1252. scale_slider_id (-1),
  1253. m_fullscreen (false),
  1254. m_minimal (false) {
  1255. setEraseColor (TQColor (0, 0, 0));
  1256. setAcceptDrops (true);
  1257. new TDEAction (i18n ("Fullscreen"), TDEShortcut (TQt::Key_F), TQT_TQOBJECT(this), TQT_SLOT (accelActivated ()), m_collection, "view_fullscreen_toggle");
  1258. setMouseTracking (true);
  1259. if (!image_data_map)
  1260. imageCacheDeleter.setObject (image_data_map, new ImageDataMap);
  1261. }
  1262. KDE_NO_CDTOR_EXPORT ViewArea::~ViewArea () {
  1263. }
  1264. KDE_NO_EXPORT void ViewArea::fullScreen () {
  1265. TQT_TQOBJECT(this)->killTimers ();
  1266. m_mouse_invisible_timer = m_repaint_timer = 0;
  1267. if (m_fullscreen) {
  1268. showNormal ();
  1269. reparent (m_parent, 0, TQPoint (0, 0), true);
  1270. static_cast <KDockWidget *> (m_parent)->setWidget (this);
  1271. for (unsigned i = 0; i < m_collection->count (); ++i)
  1272. m_collection->action (i)->setEnabled (false);
  1273. if (scale_lbl_id != -1) {
  1274. m_view->controlPanel ()->popupMenu ()->removeItem (scale_lbl_id);
  1275. m_view->controlPanel ()->popupMenu ()->removeItem (scale_slider_id);
  1276. scale_lbl_id = scale_slider_id = -1;
  1277. }
  1278. m_view->controlPanel ()->button (ControlPanel::button_playlist)->setIconSet (TQIconSet (TQPixmap (playlist_xpm)));
  1279. } else {
  1280. m_topwindow_rect = topLevelWidget ()->geometry ();
  1281. reparent (0L, 0, tqApp->desktop()->screenGeometry(this).topLeft(), true);
  1282. showFullScreen ();
  1283. for (unsigned i = 0; i < m_collection->count (); ++i)
  1284. m_collection->action (i)->setEnabled (true);
  1285. TQPopupMenu * menu = m_view->controlPanel ()->popupMenu ();
  1286. TQLabel * lbl = new TQLabel (i18n ("Scale:"), menu);
  1287. scale_lbl_id = menu->insertItem (lbl, -1, 4);
  1288. TQSlider * slider = new TQSlider (50, 150, 10, m_fullscreen_scale, Qt::Horizontal, menu);
  1289. connect (slider, TQT_SIGNAL (valueChanged (int)), this, TQT_SLOT (scale (int)));
  1290. scale_slider_id = menu->insertItem (slider, -1, 5);
  1291. m_view->controlPanel ()->button (ControlPanel::button_playlist)->setIconSet (TQIconSet (TQPixmap (normal_window_xpm)));
  1292. }
  1293. m_fullscreen = !m_fullscreen;
  1294. m_view->controlPanel()->popupMenu ()->setItemChecked (ControlPanel::menu_fullscreen, m_fullscreen);
  1295. #ifdef HAVE_CAIRO
  1296. if (surface->surface) {
  1297. cairo_surface_destroy (surface->surface);
  1298. surface->surface = 0L;
  1299. }
  1300. #endif
  1301. if (m_fullscreen) {
  1302. m_mouse_invisible_timer = startTimer(MOUSE_INVISIBLE_DELAY);
  1303. } else {
  1304. if (m_mouse_invisible_timer) {
  1305. killTimer (m_mouse_invisible_timer);
  1306. m_mouse_invisible_timer = 0;
  1307. }
  1308. unsetCursor();
  1309. }
  1310. }
  1311. void ViewArea::minimalMode () {
  1312. m_minimal = !m_minimal;
  1313. TQT_TQOBJECT(this)->killTimers ();
  1314. m_mouse_invisible_timer = m_repaint_timer = 0;
  1315. if (m_minimal) {
  1316. m_view->setViewOnly ();
  1317. m_view->setControlPanelMode (KMPlayer::View::CP_AutoHide);
  1318. m_view->setNoInfoMessages (true);
  1319. m_view->controlPanel ()->button (ControlPanel::button_playlist)->setIconSet (TQIconSet (TQPixmap (normal_window_xpm)));
  1320. } else {
  1321. m_view->setControlPanelMode (KMPlayer::View::CP_Show);
  1322. m_view->setNoInfoMessages (false);
  1323. m_view->controlPanel ()->button (ControlPanel::button_playlist)->setIconSet (TQIconSet (TQPixmap (playlist_xpm)));
  1324. }
  1325. m_topwindow_rect = topLevelWidget ()->geometry ();
  1326. }
  1327. KDE_NO_EXPORT void ViewArea::accelActivated () {
  1328. m_view->controlPanel()->popupMenu ()->activateItemAt (m_view->controlPanel()->popupMenu ()->indexOf (ControlPanel::menu_fullscreen));
  1329. }
  1330. KDE_NO_EXPORT void ViewArea::mousePressEvent (TQMouseEvent * e) {
  1331. if (surface->node) {
  1332. MouseVisitor visitor (event_pointer_clicked, e->x(), e->y());
  1333. surface->node->accept (&visitor);
  1334. }
  1335. e->accept ();
  1336. }
  1337. KDE_NO_EXPORT void ViewArea::mouseDoubleClickEvent (TQMouseEvent *) {
  1338. m_view->fullScreen (); // screensaver stuff
  1339. }
  1340. KDE_NO_EXPORT void ViewArea::mouseMoveEvent (TQMouseEvent * e) {
  1341. if (e->state () == Qt::NoButton) {
  1342. int vert_buttons_pos = height () - m_view->statusBarHeight ();
  1343. int cp_height = m_view->controlPanel ()->maximumSize ().height ();
  1344. m_view->delayedShowButtons (e->y() > vert_buttons_pos-cp_height &&
  1345. e->y() < vert_buttons_pos);
  1346. }
  1347. if (surface->node) {
  1348. MouseVisitor visitor (event_pointer_moved, e->x(), e->y());
  1349. surface->node->accept (&visitor);
  1350. setCursor (visitor.cursor);
  1351. }
  1352. e->accept ();
  1353. mouseMoved (); // for m_mouse_invisible_timer
  1354. }
  1355. KDE_NO_EXPORT void ViewArea::syncVisual (const IRect & rect) {
  1356. #ifdef HAVE_CAIRO
  1357. int ex = rect.x;
  1358. if (ex > 0)
  1359. ex--;
  1360. int ey = rect.y;
  1361. if (ey > 0)
  1362. ey--;
  1363. int ew = rect.w + 2;
  1364. int eh = rect.h + 2;
  1365. if (!surface->surface)
  1366. surface->surface = cairoCreateSurface (winId (), width (), height ());
  1367. if (surface->node && (!video_node ||
  1368. !convertNode <SMIL::MediaType> (video_node)->needsVideoWidget()))
  1369. setAudioVideoGeometry (IRect (), NULL);
  1370. CairoPaintVisitor visitor (surface->surface,
  1371. Matrix (surface->bounds.x(), surface->bounds.y(), 1.0, 1.0),
  1372. IRect (ex, ey, ew, eh), paletteBackgroundColor (), true);
  1373. if (surface->node)
  1374. surface->node->accept (&visitor);
  1375. #else
  1376. repaint (TQRect(rect.x, rect.y, rect.w, rect.h), false);
  1377. #endif
  1378. if (m_repaint_timer) {
  1379. killTimer (m_repaint_timer);
  1380. m_repaint_timer = 0;
  1381. }
  1382. //XFlush (tqt_xdisplay ());
  1383. }
  1384. KDE_NO_EXPORT void ViewArea::paintEvent (TQPaintEvent * pe) {
  1385. #ifdef HAVE_CAIRO
  1386. if (surface->node)
  1387. scheduleRepaint (IRect (pe->rect ().x (), pe->rect ().y (), pe->rect ().width (), pe->rect ().height ()));
  1388. else
  1389. #endif
  1390. TQWidget::paintEvent (pe);
  1391. }
  1392. KDE_NO_EXPORT void ViewArea::scale (int val) {
  1393. m_fullscreen_scale = val;
  1394. resizeEvent (0L);
  1395. }
  1396. KDE_NO_EXPORT void ViewArea::updateSurfaceBounds () {
  1397. Single x, y, w = width (), h = height ();
  1398. h -= m_view->statusBarHeight ();
  1399. h -= m_view->controlPanel ()->isVisible ()
  1400. ? (m_view->controlPanelMode () == View::CP_Only
  1401. ? h
  1402. : (Single) m_view->controlPanel()->maximumSize ().height ())
  1403. : Single (0);
  1404. surface->resize (SRect (x, y, w, h));
  1405. Mrl *mrl = surface->node ? surface->node->mrl () : NULL;
  1406. if (m_view->keepSizeRatio () &&
  1407. w > 0 && h > 0 &&
  1408. mrl && mrl->width > 0 && mrl->height > 0) {
  1409. double wasp = (double) w / h;
  1410. double masp = (double) mrl->width / mrl->height;
  1411. if (wasp > masp) {
  1412. Single tmp = w;
  1413. w = masp * h;
  1414. x += (tmp - w) / 2;
  1415. } else {
  1416. Single tmp = h;
  1417. h = Single (w / masp);
  1418. y += (tmp - h) / 2;
  1419. }
  1420. surface->xscale = 1.0 * w / mrl->width;
  1421. surface->yscale = 1.0 * h / mrl->height;
  1422. } else {
  1423. surface->xscale = 1.0;
  1424. surface->yscale = 1.0;
  1425. }
  1426. surface->bounds = SRect (x, y, w, h);
  1427. scheduleRepaint (IRect (0, 0, width (), height ()));
  1428. }
  1429. KDE_NO_EXPORT void ViewArea::resizeEvent (TQResizeEvent *) {
  1430. if (!m_view->controlPanel ()) return;
  1431. Single x, y, w = width (), h = height ();
  1432. Single hsb = m_view->statusBarHeight ();
  1433. Single hcp = m_view->controlPanel ()->isVisible ()
  1434. ? (m_view->controlPanelMode () == View::CP_Only
  1435. ? h-hsb
  1436. : (Single) m_view->controlPanel()->maximumSize ().height ())
  1437. : Single (0);
  1438. Single wws = w;
  1439. // move controlpanel over video when autohiding and playing
  1440. Single hws = h - (m_view->controlPanelMode () == View::CP_AutoHide &&
  1441. m_view->widgetStack ()->visibleWidget () == m_view->viewer ()
  1442. ? Single (0)
  1443. : hcp) - hsb;
  1444. // now scale the regions and check if video region is already sized
  1445. if (surface->node) {
  1446. NodePtr n = surface->node;
  1447. surface = new ViewSurface (this);
  1448. surface->node = n;
  1449. }
  1450. updateSurfaceBounds ();
  1451. // finally resize controlpanel and video widget
  1452. if (m_view->controlPanel ()->isVisible ())
  1453. m_view->controlPanel ()->setGeometry (0, h-hcp-hsb, w, hcp);
  1454. if (m_view->statusBar ()->isVisible ())
  1455. m_view->statusBar ()->setGeometry (0, h-hsb, w, hsb);
  1456. if (m_fullscreen && wws == w && hws == h) {
  1457. wws = wws * m_fullscreen_scale / 100;
  1458. hws = hws * m_fullscreen_scale / 100;
  1459. x += (w - wws) / 2;
  1460. y += (h - hws) / 2;
  1461. }
  1462. if (!surface->node)
  1463. setAudioVideoGeometry (IRect (x, y, wws, hws), 0L);
  1464. }
  1465. KDE_NO_EXPORT
  1466. void ViewArea::setAudioVideoGeometry (const IRect &rect, unsigned int * bg_color) {
  1467. int x = rect.x, y = rect.y, w = rect.w, h = rect.h;
  1468. if (m_view->controlPanelMode() == View::CP_Only) {
  1469. w = h = 0;
  1470. } else if (!surface->node && m_view->keepSizeRatio ()) { // scale video widget inside region
  1471. int hfw = m_view->viewer ()->heightForWidth (w);
  1472. if (hfw > 0)
  1473. if (hfw > h) {
  1474. int old_w = w;
  1475. w = int ((1.0 * h * w)/(1.0 * hfw));
  1476. x += (old_w - w) / 2;
  1477. } else {
  1478. y += (h - hfw) / 2;
  1479. h = hfw;
  1480. }
  1481. }
  1482. m_av_geometry = TQRect (x, y, w, h);
  1483. TQRect wrect = m_view->widgetStack ()->geometry ();
  1484. if (m_av_geometry != wrect &&
  1485. !(m_av_geometry.width() <= 0 &&
  1486. wrect.width() <= 1 && wrect.height() <= 1)) {
  1487. m_view->widgetStack ()->setGeometry (x, y, w, h);
  1488. wrect.unite (m_av_geometry);
  1489. scheduleRepaint (IRect (wrect.x (), wrect.y (), wrect.width (), wrect.height ()));
  1490. }
  1491. if (bg_color)
  1492. if (TQColor (TQRgb (*bg_color)) != (m_view->viewer ()->paletteBackgroundColor ())) {
  1493. m_view->viewer()->setCurrentBackgroundColor (TQColor (TQRgb (*bg_color)));
  1494. scheduleRepaint (IRect (x, y, w, h));
  1495. }
  1496. }
  1497. KDE_NO_EXPORT void ViewArea::setAudioVideoNode (NodePtr n) {
  1498. video_node = n;
  1499. }
  1500. KDE_NO_EXPORT SurfacePtr ViewArea::getSurface (NodePtr node) {
  1501. static_cast <ViewSurface *> (surface.ptr ())->clear ();
  1502. surface->node = node;
  1503. m_view->viewer()->resetBackgroundColor ();
  1504. if (node) {
  1505. updateSurfaceBounds ();
  1506. return surface;
  1507. }
  1508. scheduleRepaint (IRect (0, 0, width (), height ()));
  1509. return 0L;
  1510. }
  1511. KDE_NO_EXPORT void ViewArea::showEvent (TQShowEvent *) {
  1512. resizeEvent (0L);
  1513. }
  1514. KDE_NO_EXPORT void ViewArea::dropEvent (TQDropEvent * de) {
  1515. m_view->dropEvent (de);
  1516. }
  1517. KDE_NO_EXPORT void ViewArea::dragEnterEvent (TQDragEnterEvent* dee) {
  1518. m_view->dragEnterEvent (dee);
  1519. }
  1520. KDE_NO_EXPORT void ViewArea::contextMenuEvent (TQContextMenuEvent * e) {
  1521. m_view->controlPanel ()->popupMenu ()->exec (e->globalPos ());
  1522. }
  1523. KDE_NO_EXPORT void ViewArea::mouseMoved () {
  1524. if (m_fullscreen) {
  1525. if (m_mouse_invisible_timer)
  1526. killTimer (m_mouse_invisible_timer);
  1527. unsetCursor ();
  1528. m_mouse_invisible_timer = startTimer (MOUSE_INVISIBLE_DELAY);
  1529. }
  1530. }
  1531. KDE_NO_EXPORT void ViewArea::scheduleRepaint (const IRect &rect) {
  1532. if (m_repaint_timer) {
  1533. m_repaint_rect = m_repaint_rect.unite (rect);
  1534. } else {
  1535. m_repaint_rect = rect;
  1536. m_repaint_timer = startTimer (10); // 100 per sec should do
  1537. }
  1538. }
  1539. KDE_NO_EXPORT void ViewArea::timerEvent (TQTimerEvent * e) {
  1540. if (e->timerId () == m_mouse_invisible_timer) {
  1541. killTimer (m_mouse_invisible_timer);
  1542. m_mouse_invisible_timer = 0;
  1543. if (m_fullscreen)
  1544. setCursor (BlankCursor);
  1545. } else if (e->timerId () == m_repaint_timer) {
  1546. killTimer (m_repaint_timer);
  1547. m_repaint_timer = 0;
  1548. //repaint (m_repaint_rect, false);
  1549. syncVisual (m_repaint_rect.intersect (IRect (0, 0, width (), height ())));
  1550. } else {
  1551. kdError () << "unknown timer " << e->timerId () << " " << m_repaint_timer << endl;
  1552. killTimer (e->timerId ());
  1553. }
  1554. }
  1555. KDE_NO_EXPORT void ViewArea::closeEvent (TQCloseEvent * e) {
  1556. //kdDebug () << "closeEvent" << endl;
  1557. if (m_fullscreen) {
  1558. fullScreen ();
  1559. if (!m_parent->topLevelWidget ()->isVisible ())
  1560. m_parent->topLevelWidget ()->show ();
  1561. e->ignore ();
  1562. } else
  1563. TQWidget::closeEvent (e);
  1564. }
  1565. #include "viewarea.moc"