3 * Copyright (C) 2016-2020 William Morrow
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
29 #include "condition.h"
32 VIcon(int w, int h, double rate)
36 this->frame_rate = rate;
56 add_image(VFrame *frm, int ww, int hh, int vcmdl)
58 VIFrame *vifrm = new VIFrame(ww, hh, vcmdl);
59 vifrm->vfrm->transfer_from(frm);
64 draw_vframe(VIconThread *vt, BC_WindowBase *wdw, int x, int y)
66 VFrame *vfrm = frame();
68 int sx0 = 0, sx1 = sx0 + vt->vw;
69 int sy0 = 0, sy1 = sy0 + vt->vh;
70 int dx0 = x, dx1 = dx0 + w;
71 int dy0 = y, dy1 = dy0 + h;
72 if( (x=vt->draw_x0-dx0) > 0 ) { sx0 += (x*vt->vw)/w; dx0 = vt->draw_x0; }
73 if( (x=dx1-vt->draw_x1) > 0 ) { sx1 -= (x*vt->vw)/w; dx1 = vt->draw_x1; }
74 if( (y=vt->draw_y0-dy0) > 0 ) { sy0 += (y*vt->vh)/h; dy0 = vt->draw_y0; }
75 if( (y=dy1-vt->draw_y1) > 0 ) { sy1 -= (y*vt->vh)/h; dy1 = vt->draw_y1; }
76 int sw = sx1 - sx0, sh = sy1 - sy0;
77 int dw = dx1 - dx0, dh = dy1 - dy0;
78 if( dw > 0 && dh > 0 && sw > 0 && sh > 0 )
79 wdw->draw_vframe(vfrm, dx0,dy0, dw,dh, sx0,sy0, sw,sh);
83 int VIconThread::cursor_inside(int x, int y)
85 if( !viewing ) return 0;
86 int vx = viewing->get_vx();
87 if( x < vx || x >= vx+vw ) return 0;
88 int vy = viewing->get_vy();
89 if( y < vy || y >= vy+vh ) return 0;
94 set_drawing_area(int x0, int y0, int x1, int y1)
96 draw_x0 = x0; draw_y0 = y0;
97 draw_x1 = x1; draw_y1 = y1;
100 VIcon *VIconThread::low_vicon()
102 if( !t_heap.size() ) return 0;
103 VIcon *vip = t_heap[0];
108 void VIconThread::remove_vicon(int i)
110 if( t_heap[i] == solo ) solo = 0;
111 int sz = t_heap.size();
112 for( int k; (k=2*(i+1)) < sz; i=k ) {
113 if( t_heap[k]->age > t_heap[k-1]->age ) --k;
114 t_heap[i] = t_heap[k];
116 VIcon *last = t_heap[--sz];
117 t_heap.remove_number(sz);
118 double age = last->age;
119 for( int k; i>0 && age<t_heap[k=(i-1)/2]->age; i=k )
120 t_heap[i] = t_heap[k];
126 VIconThread(BC_WindowBase *wdw, int vw, int vh, int view_w, int view_h)
130 this->vw = vw; this->vh = vh;
131 this->view_w = view_w; this->view_h = view_h;
132 this->view_win = 0; this->vicon = 0;
133 this->viewing = 0; this->solo = 0;
134 this->draw_x0 = 0; this->draw_x1 = wdw->get_w();
135 this->draw_y0 = 0; this->draw_y1 = wdw->get_h();
136 draw_lock = new Condition(0, "VIconThread::draw_lock", 1);
138 this->refresh_rate = VICON_RATE;
139 this->draw_flash = 0;
153 if( Thread::running() ) {
157 t_heap.remove_all_objects();
165 wdw->lock_window("VIconThread::start_drawing");
167 wdw->set_active_subwindow(view_win);
168 if( interrupted < 0 )
171 timer->subtract(-stop_age);
173 wdw->unlock_window();
179 wdw->lock_window("VIconThread::stop_drawing");
183 stop_age = timer->get_difference();
184 wdw->unlock_window();
191 viewing->stop_audio();
196 int VIconThread::keypress_event(int key)
198 if( key != ESC ) return 0;
204 visible(VIcon *vicon, int x, int y)
206 if( vicon->hidden ) return false;
207 if( y+vicon->h <= draw_y0 ) return false;
208 if( y >= draw_y1 ) return false;
209 if( x+vicon->w <= draw_x0 ) return false;
210 if( x >= draw_x1 ) return false;
214 int ViewPopup::keypress_event()
216 int key = get_keypress();
217 return vt->keypress_event(key);
221 ViewPopup::ViewPopup(VIconThread *vt, int x, int y, int w, int h)
222 : BC_Popup(vt->wdw, x, y, w, h, BLACK)
227 ViewPopup::~ViewPopup()
229 vt->wdw->set_active_subwindow(0);
232 ViewPopup *VIconThread::new_view_window(ViewPopup *vpopup)
234 BC_WindowBase *parent = wdw->get_parent();
235 XineramaScreenInfo *info = parent->get_xinerama_info(-1);
236 int cx = info ? info->x_org + info->width/2 : parent->get_root_w(0)/2;
237 int cy = info ? info->y_org + info->height/2 : parent->get_root_h(0)/2;
238 int vx = viewing->get_vx(), rx = 0;
239 int vy = viewing->get_vy(), ry = 0;
240 wdw->get_root_coordinates(vx, vy, &rx, &ry);
241 rx += (rx >= cx ? -view_w+viewing->w/4 : viewing->w-viewing->w/4);
242 ry += (ry >= cy ? -view_h+viewing->h/4 : viewing->h-viewing->h/4);
244 vpopup->reposition_window(rx, ry, view_w, view_h);
246 vpopup = new ViewPopup(this, rx, ry, view_w, view_h);
247 wdw->set_active_subwindow(vpopup);
255 for( int i=t_heap.size(); --i>=0; ) t_heap[i]->reset();
257 img_dirty = win_dirty = 0;
260 void VIconThread::add_vicon(VIcon *vip)
262 double age = vip->age;
263 int i = t_heap.size(); t_heap.append(vip);
264 for( int k; i>0 && age<t_heap[(k=(i-1)/2)]->age; i=k )
265 t_heap[i] = t_heap[k];
269 int VIconThread::del_vicon(VIcon *vicon)
271 int i = t_heap.size();
272 while( --i >= 0 && t_heap[i] != vicon );
273 if( i < 0 ) return 0;
278 void ViewPopup::draw_vframe(VFrame *frame)
281 BC_WindowBase::draw_vframe(frame, 0,0, get_w(),get_h());
284 void VIconThread::set_view_popup(VIcon *vicon)
286 if( viewing == vicon && !this->vicon ) return;
288 if( interrupted ) update_view(vicon ? 1 : 0);
292 void VIconThread::close_view_popup()
298 update_view(int do_audio)
300 if( viewing ) viewing->stop_audio();
301 delete view_win; view_win = 0;
303 if( (viewing=vicon) != 0 && (vfrm=viewing->frame()) != 0 ) {
304 view_win = new_view_window(0);
305 view_win->draw_vframe(vfrm);
307 view_win->show_window();
308 if( do_audio ) vicon->start_audio();
310 wdw->set_active_subwindow(view_win);
314 int VIconThread::zoom_scale(int dir)
317 if( !viewing || !view_win || !(vfrm=viewing->frame()) ) return 0;
318 int view_h = this->view_h;
319 view_h += dir*view_h/10 + dir;
320 bclamp(view_h, 16,512);
321 this->view_h = view_h;
322 this->view_w = view_h * vw/vh;
323 new_view_window(view_win);
324 view_win->draw_vframe(vfrm);
333 for( int i=0; i<t_heap.size(); ++i )
340 if( !img_dirty && !win_dirty ) return;
341 if( img_dirty ) wdw->flash();
342 if( win_dirty && view_win ) view_win->flash();
343 win_dirty = img_dirty = 0;
349 int x = vicon->get_vx(), y = vicon->get_vy();
350 int draw_img = visible(vicon, x, y);
351 int draw_win = view_win && viewing == vicon ? 1 : 0;
352 if( !draw_img && !draw_win ) return 0;
353 VFrame *vfrm = vicon->frame();
354 if( !vfrm ) return 0;
356 vicon->draw_vframe(this, wdw, x, y);
360 view_win->draw_vframe(vfrm);
366 void VIconThread::hide_vicons(int v)
368 for( int i=0; i<t_heap.size(); ++i ) {
369 t_heap[i]->hidden = v;
374 int VIconThread::show_vicon(VIcon *next)
376 now = timer->get_difference();
377 if( now >= draw_flash ) return 1;
379 if( !next->seq_no ) {
380 next->cycle_start = now;
381 if( next->playing_audio > 0 )
384 int64_t ref_no = (now - next->cycle_start) / 1000. * refresh_rate;
385 int count = ref_no - next->seq_no;
386 if( count < 1 ) count = 1;
387 ref_no = next->seq_no + count;
388 next->age = next->cycle_start + 1000. * ref_no / refresh_rate;
389 if( !next->set_seq_no(ref_no) )
390 next->age = now + 1000.;
398 draw_lock->lock("VIconThread::run 0");
400 wdw->lock_window("BC_WindowBase::run 1");
403 draw_flash = 1000 / refresh_rate;
405 while( !interrupted ) {
406 if( viewing != vicon )
409 VIcon *next = low_vicon();
410 while( !interrupted && next && next->age < draw_flash ) {
411 if( show_vicon(next) ) break;
417 if( draw_flash < now+1 )
422 wdw->unlock_window();
423 while( !interrupted ) {
424 now = timer->get_difference();
425 int64_t ms = draw_flash - now;
427 if( ms > 100 ) ms = 100;
430 wdw->lock_window("BC_WindowBase::run 2");
431 now = timer->get_difference();
432 int64_t late = now - draw_flash;
433 if( late < 1000 ) flash();
434 int64_t ref_no = now / 1000. * refresh_rate;
435 int64_t count = ref_no - seq_no;
436 if( count < 1 ) count = 1;
438 draw_flash = seq_no * 1000. / refresh_rate;
440 if( viewing != vicon )
444 wdw->unlock_window();
449 void VIcon::init_audio(int audio_size)
451 this->audio_size = audio_size;
452 audio_data = new uint8_t[audio_size];
453 memset(audio_data, 0, audio_size);
456 void VIcon::dump(const char *dir)
459 for( int i=0; i<images.size(); ++i ) {
460 VFrame *vfrm = images[i]->vfrm;
461 if( !vfrm ) continue;
462 char fn[1024]; sprintf(fn,"%s/img%05d.png",dir,i);