Files
neutrino/src/driver/glcd/glcd.cpp
Thilo Graf 04e39c2f43 src/driver/glcd: remove obsolete FSF address
Supplement to : "src/driver/glcd: code formatting"
2023-08-15 21:12:30 +02:00

1958 lines
48 KiB
C++

/*
Neutrino graphlcd daemon thread
(C) 2012-2014 by martii
License: GPL
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <global.h>
#include <neutrino.h>
#include <algorithm>
#include <system/debug.h>
#include <timerdclient/timerdclient.h>
#include <system/helpers.h>
#include <system/set_threadname.h>
#include <driver/audioplay.h>
#include <gui/infoviewer.h>
#include <gui/movieplayer.h>
#include <driver/pictureviewer/pictureviewer.h>
#include <hardware_caps.h>
#include <eitd/sectionsd.h>
#include <math.h>
#include "glcd.h"
#include "analogclock.h"
#include "digitalclock.h"
#include "simpleclock.h"
#include "weather.h"
#include "zlib.h"
#include "png.h"
#include "jpeglib.h"
#define ICONSEXT ".png"
static const char *kDefaultConfigFile = "/etc/graphlcd.conf";
static cGLCD *cglcd = NULL;
extern CRemoteControl *g_RemoteControl;
extern CPictureViewer *g_PicViewer;
cGLCD::cGLCD()
{
lcd = NULL;
Logo = "";
Channel = "Neutrino";
Epg = std::string(g_info.hw_caps->boxvendor) + " " + std::string(g_info.hw_caps->boxname);
sem_init(&sem, 0, 1);
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
pthread_mutex_init(&mutex, &attr);
channelLocked = false;
timeLocked = false;
durationLocked = false;
startLocked = false;
endLocked = false;
recLocked = false;
muteLocked = false;
tsLocked = false;
ecmLocked = false;
timerLocked = false;
ddLocked = false;
txtLocked = false;
subLocked = false;
camLocked = false;
doRescan = false;
doStandby = false;
doStandbyTime = false;
doStandbyWeather = false;
doShowVolume = false;
doShowLcdIcon = false;
doSuspend = false;
doExit = false;
doMirrorOSD = false;
fontsize_channel = 0;
fontsize_epg = 0;
fontsize_time = 0;
fontsize_duration = 0;
fontsize_start = 0;
fontsize_end = 0;
fontsize_smalltext = 0;
fonts_initialized = false;
ismediaplayer = false;
doScrollChannel = false;
doScrollEpg = false;
percent_channel = 0;
percent_time = 0;
percent_duration = 0;
percent_start = 0;
percent_end = 0;
percent_smalltext = 0;
percent_epg = 0;
percent_bar = 0;
percent_logo = 0;
percent_logo_width = 0;
power_state = 1;
Scale = 0;
bitmap = NULL;
blitFlag = true;
timeout_cnt = 0;
locked_countdown = false;
time_thread_started = false;
config_mode = false;
cglcd = this;
if (!g_settings.glcd_enable)
doSuspend = true;
if (pthread_create(&thrGLCD, 0, cGLCD::Run, this) != 0)
fprintf(stderr, "ERROR: pthread_create(cGLCD::Init)\n");
if (pthread_create(&thrTimeThread, 0, cGLCD::TimeThread, this) != 0)
fprintf(stderr, "ERROR: pthread_create(cGLCD::TimeThread)\n");
InitAnalogClock();
InitDigitalClock();
InitSimpleClock();
Update();
}
void cGLCD::Lock(void)
{
if (cglcd)
{
pthread_mutex_lock(&cglcd->mutex);
}
}
void cGLCD::Unlock(void)
{
if (cglcd)
{
pthread_mutex_unlock(&cglcd->mutex);
}
}
cGLCD::~cGLCD()
{
Suspend();
cglcd = NULL;
if (lcd)
{
lcd->DeInit();
delete lcd;
}
sem_destroy(&sem);
pthread_mutex_destroy(&mutex);
}
cGLCD *cGLCD::getInstance()
{
if (!cglcd)
cglcd = new cGLCD;
return cglcd;
}
uint32_t cGLCD::ColorConvert3to1(uint32_t red, uint32_t green, uint32_t blue)
{
unsigned int color_red_tmp = (static_cast<int>(red) * 2.55) + 1;
unsigned int color_green_tmp = (static_cast<int>(green) * 2.55) + 1;
unsigned int color_blue_tmp = (static_cast<int>(blue) * 2.55) + 1;
uint32_t color = 0xff;
color <<= 8;
color |= color_red_tmp;
color <<= 8;
color |= color_green_tmp;
color <<= 8;
color |= color_blue_tmp;
return color;
}
void cGLCD::Exec()
{
SNeutrinoGlcdTheme &t = g_settings.glcd_theme;
if (!lcd)
return;
bitmap->Clear(ColorConvert3to1(t.glcd_background_color_red, t.glcd_background_color_green, t.glcd_background_color_blue));
if (Channel.compare("Neutrino") == 0)
{
if (imageShow(DATADIR "/neutrino/icons/start.jpg", 0, 0, 0, 0, false, true, true, false, false))
{
GLCD::cFont font_tmp;
int fw = font_epg.Width(Epg);
fw = (fw == 0) ? 1 : fw;
font_tmp.LoadFT2(t.glcd_font, "UTF-8", fontsize_epg * bitmap->Width() / fw);
fw = font_tmp.Width(Epg);
int fh = font_tmp.Height(Epg);
drawText(std::max(2, (bitmap->Width() - fw) / 2),
std::max(2, (bitmap->Height() - fh) / 2), bitmap->Width(), fw, Epg,
&font_tmp, ColorConvert3to1(t.glcd_foreground_color_red, t.glcd_foreground_color_green, t.glcd_foreground_color_blue), GLCD::cColor::Transparent, true, 0, ALIGN_NONE);
lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height());
lcd->Refresh(true);
}
else
{
cglcd->bitmap->Clear(ColorConvert3to1(t.glcd_background_color_red, t.glcd_background_color_green, t.glcd_background_color_blue));
cglcd->lcd->Refresh(true);
}
return;
}
if (doStandbyTime || doStandbyWeather)
{
if (t.glcd_standby_clock == CLOCK_ANALOG)
{
ShowAnalogClock(tm->tm_hour, tm->tm_min, tm->tm_sec, bitmap->Width() / 2, bitmap->Height() / 2);
}
else if (t.glcd_standby_clock == CLOCK_DIGITAL)
{
ShowDigitalClock(tm->tm_hour, tm->tm_min);
}
else if (t.glcd_standby_clock > CLOCK_OFF)
{
ShowSimpleClock(strftime("%H:%M", tm), t.glcd_standby_clock);
}
if (t.glcd_standby_weather == 1 && t.glcd_standby_clock != CLOCK_ANALOG)
{
ShowWeather(true);
}
lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height());
lcd->Refresh(false);
return;
}
if (t.glcd_background_image != "")
imageShow(t.glcd_background_image, 0, 0, 0, 0, false, true, true, false, false);
if (t.glcd_weather)
ShowWeather(false);
switch (CAudioPlayer::getInstance()->getState())
{
case CBaseDec::REV:
ismediaplayer = true;
Logo = ICONSDIR "/" NEUTRINO_ICON_REW ICONSEXT;
break;
case CBaseDec::FF:
ismediaplayer = true;
Logo = ICONSDIR "/" NEUTRINO_ICON_FF ICONSEXT;
break;
case CBaseDec::PAUSE:
ismediaplayer = true;
Logo = ICONSDIR "/" NEUTRINO_ICON_PAUSE ICONSEXT;
break;
case CBaseDec::PLAY:
ismediaplayer = true;
Logo = ICONSDIR "/" NEUTRINO_ICON_PLAY ICONSEXT;
break;
default:
ismediaplayer = false;
;
}
switch (CMoviePlayerGui::getInstance().getState())
{
case CMoviePlayerGui::REW:
ismediaplayer = true;
Logo = ICONSDIR "/" NEUTRINO_ICON_REW ICONSEXT;
break;
case CMoviePlayerGui::FF:
ismediaplayer = true;
Logo = ICONSDIR "/" NEUTRINO_ICON_FF ICONSEXT;
break;
case CMoviePlayerGui::PAUSE:
ismediaplayer = true;
Logo = ICONSDIR "/" NEUTRINO_ICON_PAUSE ICONSEXT;
break;
case CMoviePlayerGui::PLAY:
ismediaplayer = true;
Logo = ICONSDIR "/" NEUTRINO_ICON_PLAY ICONSEXT;
break;
default:
ismediaplayer = false;
;
}
switch (CRecordManager::getInstance()->GetRecordMode())
{
case CRecordManager::RECMODE_REC_TSHIFT:
recLocked = true;
tsLocked = true;
break;
case CRecordManager::RECMODE_REC:
recLocked = true;
break;
case CRecordManager::RECMODE_TSHIFT:
tsLocked = true;
break;
default:
recLocked = false;
tsLocked = false;
break;
}
int icon_start_width = 0, icon_start_height = 0;
g_PicViewer->getSize(Logo.c_str(), &icon_start_width, &icon_start_height);
if (t.glcd_logo && percent_logo &&
showImage(channel_id, Channel, t.glcd_logo_x_position + (bitmap->Width() - (percent_logo_width * bitmap->Width() / 100)) / 2, t.glcd_logo_y_position, percent_logo_width * bitmap->Width() / 100, percent_logo * bitmap->Height() / 100, true, false))
{
doScrollChannel = false;
scrollChannelSkip = 0;
}
else if (percent_logo && icon_start_width && icon_start_height &&
doShowLcdIcon && showImage(Logo, icon_start_width, icon_start_height, t.glcd_logo_x_position, t.glcd_logo_y_position, bitmap->Width(), percent_logo * bitmap->Height() / 100, true, false))
{
doScrollChannel = false;
scrollChannelSkip = 0;
}
else if (percent_channel)
{
if (ChannelWidth)
{
if (scrollChannelForward)
{
if (ChannelWidth - scrollChannelSkip < bitmap->Width())
scrollChannelForward = false;
}
else if (scrollChannelSkip <= 0)
{
scrollChannelSkip = 0;
doScrollChannel = false;
}
drawText(t.glcd_channel_x_position + scrollChannelOffset,
t.glcd_channel_y_position, bitmap->Width(), ChannelWidth, Channel,
&font_channel, ColorConvert3to1(t.glcd_foreground_color_red, t.glcd_foreground_color_green, t.glcd_foreground_color_blue), GLCD::cColor::Transparent, true, scrollChannelSkip, t.glcd_channel_align);
if (scrollChannelOffset > 0)
scrollChannelOffset -= g_settings.glcd_scroll_speed;
if (scrollChannelOffset < 0)
scrollChannelOffset = 0;
if (scrollChannelOffset == 0)
{
if (scrollChannelForward)
scrollChannelSkip += g_settings.glcd_scroll_speed;
else
scrollChannelSkip -= g_settings.glcd_scroll_speed;
}
}
}
if (percent_epg)
{
if (EpgWidth)
{
if (scrollEpgForward)
{
if (EpgWidth - scrollEpgSkip < bitmap->Width())
scrollEpgForward = false;
}
else if (scrollEpgSkip <= 0)
{
scrollEpgSkip = 0;
doScrollEpg = false;
}
drawText(t.glcd_epg_x_position + scrollEpgOffset,
t.glcd_epg_y_position, bitmap->Width(), EpgWidth, Epg,
&font_epg, ColorConvert3to1(t.glcd_foreground_color_red, t.glcd_foreground_color_green, t.glcd_foreground_color_blue), GLCD::cColor::Transparent, true, scrollEpgSkip, t.glcd_epg_align);
if (scrollEpgOffset > 0)
scrollEpgOffset -= g_settings.glcd_scroll_speed;
if (scrollEpgOffset < 0)
scrollEpgOffset = 0;
if (scrollEpgOffset == 0)
{
if (scrollEpgForward)
scrollEpgSkip += g_settings.glcd_scroll_speed;
else
scrollEpgSkip -= g_settings.glcd_scroll_speed;
}
}
}
if (percent_bar && t.glcd_progressbar)
{
showProgressBarBorder(
t.glcd_progressbar_x_position,
t.glcd_progressbar_y_position,
t.glcd_progressbar_width,
t.glcd_progressbar_y_position + t.glcd_progressbar_percent,
Scale,
GLCD::cColor::Gray,
ColorConvert3to1(t.glcd_progressbar_color_red, t.glcd_progressbar_color_green, t.glcd_progressbar_color_blue)
);
}
if (percent_time && t.glcd_time)
{
Lock();
Time = strftime("%H:%M", tm);
TimeWidth = font_time.Width(Time);
Unlock();
drawText(t.glcd_time_x_position,
t.glcd_time_y_position, bitmap->Width() - 1, TimeWidth, Time,
&font_time, ColorConvert3to1(t.glcd_foreground_color_red, t.glcd_foreground_color_green, t.glcd_foreground_color_blue), GLCD::cColor::Transparent, true, 0, t.glcd_time_align);
}
if (percent_duration && t.glcd_duration)
{
Lock();
Duration = stagingDuration;
DurationWidth = font_duration.Width(Duration);
Unlock();
drawText(t.glcd_duration_x_position,
t.glcd_duration_y_position, bitmap->Width() - 1, DurationWidth, Duration,
&font_duration, ColorConvert3to1(t.glcd_foreground_color_red, t.glcd_foreground_color_green, t.glcd_foreground_color_blue), GLCD::cColor::Transparent, true, 0, t.glcd_duration_align);
}
if (percent_start && t.glcd_start)
{
Lock();
Start = stagingStart;
StartWidth = font_start.Width(Start);
Unlock();
drawText(t.glcd_start_x_position,
t.glcd_start_y_position, bitmap->Width() - 1, StartWidth, Start,
&font_start, ColorConvert3to1(t.glcd_foreground_color_red, t.glcd_foreground_color_green, t.glcd_foreground_color_blue), GLCD::cColor::Transparent, true, 0, t.glcd_start_align);
}
if (percent_end && t.glcd_end)
{
Lock();
End = stagingEnd;
EndWidth = font_end.Width(End);
Unlock();
drawText(t.glcd_end_x_position,
t.glcd_end_y_position, bitmap->Width() - 1, EndWidth, End,
&font_end, ColorConvert3to1(t.glcd_foreground_color_red, t.glcd_foreground_color_green, t.glcd_foreground_color_blue), GLCD::cColor::Transparent, true, 0, t.glcd_end_align);
}
if (percent_smalltext && !doStandby)
{
Lock();
SmalltextWidth = font_smalltext.Width(Smalltext);
Unlock();
if (access("/tmp/ecm.info", F_OK) == 0)
{
struct stat buf;
stat("/tmp/ecm.info", &buf);
if (buf.st_size > 0)
ecmLocked = true;
else
ecmLocked = false;
}
std::string smalltext;
if (t.glcd_icon_rec_x_position)
{
smalltext = "REC";
if (recLocked)
{
drawText(t.glcd_icon_rec_x_position, t.glcd_icons_y_position,
bitmap->Width() - 1, SmalltextWidth, smalltext, &font_smalltext, GLCD::cColor::Red,
GLCD::cColor::Transparent, true, 0, 0);
}
else
{
drawText(t.glcd_icon_rec_x_position, t.glcd_icons_y_position,
bitmap->Width() - 1, SmalltextWidth, smalltext, &font_smalltext, GLCD::cColor::Gray,
GLCD::cColor::Transparent, true, 0, 0);
}
}
if (t.glcd_icon_mute_x_position)
{
smalltext = "MUTE";
if (muteLocked)
{
drawText(t.glcd_icon_mute_x_position, t.glcd_icons_y_position,
bitmap->Width() - 1, SmalltextWidth, smalltext, &font_smalltext, GLCD::cColor::Red,
GLCD::cColor::Transparent, true, 0, 0);
}
else
{
drawText(t.glcd_icon_mute_x_position, t.glcd_icons_y_position,
bitmap->Width() - 1, SmalltextWidth, smalltext, &font_smalltext, GLCD::cColor::Gray,
GLCD::cColor::Transparent, true, 0, 0);
}
}
if (t.glcd_icon_ts_x_position)
{
smalltext = "TS";
if (tsLocked)
{
drawText(t.glcd_icon_ts_x_position, t.glcd_icons_y_position,
bitmap->Width() - 1, SmalltextWidth, smalltext, &font_smalltext, GLCD::cColor::Yellow,
GLCD::cColor::Transparent, true, 0, 0);
}
else
{
drawText(t.glcd_icon_ts_x_position, t.glcd_icons_y_position,
bitmap->Width() - 1, SmalltextWidth, smalltext, &font_smalltext, GLCD::cColor::Gray,
GLCD::cColor::Transparent, true, 0, 0);
}
}
#if 0
if (t.glcd_icon_ecm_x_position)
{
smalltext = "ECM";
if (ecmLocked)
{
drawText(t.glcd_icon_ecm_x_position, t.glcd_icons_y_position,
bitmap->Width() - 1, SmalltextWidth, smalltext, &font_smalltext, GLCD::cColor::Green,
GLCD::cColor::Transparent, true, 0, 0);
}
else
{
drawText(t.glcd_icon_ecm_x_position, t.glcd_icons_y_position,
bitmap->Width() - 1, SmalltextWidth, smalltext, &font_smalltext, GLCD::cColor::Gray,
GLCD::cColor::Transparent, true, 0, 0);
}
}
#endif
if (t.glcd_icon_timer_x_position)
{
smalltext = "TIMER";
if (timerLocked)
{
drawText(t.glcd_icon_timer_x_position, t.glcd_icons_y_position,
bitmap->Width() - 1, SmalltextWidth, smalltext, &font_smalltext, GLCD::cColor::Yellow,
GLCD::cColor::Transparent, true, 0, 0);
}
else
{
drawText(t.glcd_icon_timer_x_position, t.glcd_icons_y_position,
bitmap->Width() - 1, SmalltextWidth, smalltext, &font_smalltext, GLCD::cColor::Gray,
GLCD::cColor::Transparent, true, 0, 0);
}
}
if (t.glcd_icon_dd_x_position)
{
smalltext = "DD";
if (ddLocked)
{
drawText(t.glcd_icon_dd_x_position, t.glcd_icons_y_position,
bitmap->Width() - 1, SmalltextWidth, smalltext, &font_smalltext, GLCD::cColor::Green,
GLCD::cColor::Transparent, true, 0, 0);
}
else
{
drawText(t.glcd_icon_dd_x_position, t.glcd_icons_y_position,
bitmap->Width() - 1, SmalltextWidth, smalltext, &font_smalltext, GLCD::cColor::Gray,
GLCD::cColor::Transparent, true, 0, 0);
}
}
if (t.glcd_icon_txt_x_position)
{
if (ismediaplayer)
{
smalltext = "SUB";
if (subLocked)
{
drawText(t.glcd_icon_txt_x_position, t.glcd_icons_y_position,
bitmap->Width() - 1, SmalltextWidth, smalltext, &font_smalltext, GLCD::cColor::Green,
GLCD::cColor::Transparent, true, 0, 0);
}
else
{
drawText(t.glcd_icon_txt_x_position, t.glcd_icons_y_position,
bitmap->Width() - 1, SmalltextWidth, smalltext, &font_smalltext, GLCD::cColor::Gray,
GLCD::cColor::Transparent, true, 0, 0);
}
}
else
{
smalltext = "TXT";
if (txtLocked)
{
drawText(t.glcd_icon_txt_x_position, t.glcd_icons_y_position,
bitmap->Width() - 1, SmalltextWidth, smalltext, &font_smalltext, GLCD::cColor::Green,
GLCD::cColor::Transparent, true, 0, 0);
}
else
{
drawText(t.glcd_icon_txt_x_position, t.glcd_icons_y_position,
bitmap->Width() - 1, SmalltextWidth, smalltext, &font_smalltext, GLCD::cColor::Gray,
GLCD::cColor::Transparent, true, 0, 0);
}
}
}
if (t.glcd_icon_cam_x_position)
{
smalltext = "CAM";
if (camLocked)
{
drawText(t.glcd_icon_cam_x_position, t.glcd_icons_y_position,
bitmap->Width() - 1, SmalltextWidth, smalltext, &font_smalltext, GLCD::cColor::Green,
GLCD::cColor::Transparent, true, 0, 0);
}
else
{
drawText(t.glcd_icon_cam_x_position, t.glcd_icons_y_position,
bitmap->Width() - 1, SmalltextWidth, smalltext, &font_smalltext, GLCD::cColor::Gray,
GLCD::cColor::Transparent, true, 0, 0);
}
}
}
lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height());
lcd->Refresh(false);
}
void cGLCD::updateFonts()
{
SNeutrinoGlcdTheme &t = g_settings.glcd_theme;
percent_logo = std::min(t.glcd_logo_percent, 100);
percent_logo_width = std::min(t.glcd_logo_width_percent, 100);
percent_channel = std::min(t.glcd_channel_percent, 100);
percent_epg = std::min(t.glcd_epg_percent, 100);
percent_bar = std::min(t.glcd_progressbar_percent, 100);
percent_time = std::min(t.glcd_time_percent, 100);
percent_duration = std::min(t.glcd_duration_percent, 100);
percent_start = std::min(t.glcd_start_percent, 100);
percent_end = std::min(t.glcd_end_percent, 100);
percent_smalltext = std::min(t.glcd_icons_percent, 100);
// calculate height
int fontsize_channel_new = percent_channel * cglcd->lcd->Height() / 100;
int fontsize_epg_new = percent_epg * cglcd->lcd->Height() / 100;
int fontsize_time_new = percent_time * cglcd->lcd->Height() / 100;
int fontsize_duration_new = percent_duration * cglcd->lcd->Height() / 100;
int fontsize_start_new = percent_start * cglcd->lcd->Height() / 100;
int fontsize_end_new = percent_end * cglcd->lcd->Height() / 100;
int fontsize_smalltext_new = percent_smalltext * cglcd->lcd->Height() / 100;
if (!fonts_initialized || (fontsize_channel_new != fontsize_channel))
{
fontsize_channel = fontsize_channel_new;
if (!font_channel.LoadFT2(t.glcd_font, "UTF-8", fontsize_channel))
{
t.glcd_font = g_settings.font_file;
font_channel.LoadFT2(t.glcd_font, "UTF-8", fontsize_channel);
}
}
if (!fonts_initialized || (fontsize_epg_new != fontsize_epg))
{
fontsize_epg = fontsize_epg_new;
if (!font_epg.LoadFT2(t.glcd_font, "UTF-8", fontsize_epg))
{
t.glcd_font = g_settings.font_file;
font_epg.LoadFT2(t.glcd_font, "UTF-8", fontsize_epg);
}
}
if (!fonts_initialized || (fontsize_time_new != fontsize_time))
{
fontsize_time = fontsize_time_new;
if (!font_time.LoadFT2(t.glcd_font, "UTF-8", fontsize_time))
{
t.glcd_font = g_settings.font_file;
font_time.LoadFT2(t.glcd_font, "UTF-8", fontsize_time);
}
}
if (!fonts_initialized || (fontsize_duration_new != fontsize_duration))
{
fontsize_duration = fontsize_duration_new;
if (!font_duration.LoadFT2(t.glcd_font, "UTF-8", fontsize_duration))
{
t.glcd_font = g_settings.font_file;
font_duration.LoadFT2(t.glcd_font, "UTF-8", fontsize_duration);
}
}
if (!fonts_initialized || (fontsize_start_new != fontsize_start))
{
fontsize_start = fontsize_start_new;
if (!font_start.LoadFT2(t.glcd_font, "UTF-8", fontsize_start))
{
t.glcd_font = g_settings.font_file;
font_start.LoadFT2(t.glcd_font, "UTF-8", fontsize_start);
}
}
if (!fonts_initialized || (fontsize_end_new != fontsize_end))
{
fontsize_end = fontsize_end_new;
if (!font_end.LoadFT2(t.glcd_font, "UTF-8", fontsize_end))
{
t.glcd_font = g_settings.font_file;
font_end.LoadFT2(t.glcd_font, "UTF-8", fontsize_end);
}
}
if (!fonts_initialized || (fontsize_smalltext_new != fontsize_smalltext))
{
fontsize_smalltext = fontsize_smalltext_new;
if (!font_smalltext.LoadFT2(t.glcd_font, "UTF-8", fontsize_smalltext))
{
t.glcd_font = g_settings.font_file;
font_smalltext.LoadFT2(t.glcd_font, "UTF-8", fontsize_smalltext);
}
}
WeatherUpdateFonts();
fonts_initialized = true;
}
bool cGLCD::getBoundingBox(uint32_t *buffer, int width, int height, int &bb_x, int &bb_y, int &bb_w, int &bb_h)
{
if (!width || !height)
{
bb_x = bb_y = bb_w = bb_h = 0;
return false;
}
int y_min = height;
uint32_t *b = buffer;
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++, b++)
if (*b)
{
y_min = y;
goto out1;
}
out1:
int y_max = y_min;
b = buffer + height * width - 1;
for (int y = height - 1; y_min < y; y--)
for (int x = 0; x < width; x++, b--)
if (*b)
{
y_max = y;
goto out2;
}
out2:
int x_min = width;
for (int x = 0; x < width; x++)
{
b = buffer + x + y_min * width;
for (int y = y_min; y < y_max; y++, b += width)
if (*b)
{
x_min = x;
goto out3;
}
}
out3:
int x_max = x_min;
for (int x = width - 1; x_min < x; x--)
{
b = buffer + x + y_min * width;
for (int y = y_min; y < y_max; y++, b += width)
if (*b)
{
x_max = x;
goto out4;
}
}
out4:
bb_x = x_min;
bb_y = y_min;
bb_w = 1 + x_max - x_min;
bb_h = 1 + y_max - y_min;
if (bb_x < 0)
bb_x = 0;
if (bb_y < 0)
bb_y = 0;
return true;
}
void *cGLCD::Run(void *arg)
{
cGLCD *me = (cGLCD *)arg;
me->Run();
pthread_exit(NULL);
}
void cGLCD::CountDown()
{
if (timeout_cnt > 0)
{
timeout_cnt--;
if (timeout_cnt == 0)
{
UpdateBrightness();
cglcd->locked_countdown = false;
}
}
}
void cGLCD::WakeUp()
{
int tmp = atoi(g_settings.glcd_brightness_dim_time.c_str());
if (tmp > 0)
{
timeout_cnt = (unsigned int)tmp;
UpdateBrightness();
cglcd->locked_countdown = true;
}
}
void *cGLCD::TimeThread(void *p)
{
set_threadname("cGLCD:Time");
((cGLCD *)p)->time_thread_started = true;
while (((cGLCD *)p)->time_thread_started)
{
sleep(1);
if (!cglcd->doExit && (
cglcd->locked_countdown == true
|| cglcd->channelLocked == true
|| cglcd->timeLocked == true
|| cglcd->durationLocked == true
|| cglcd->startLocked == true
|| cglcd->endLocked == true
|| cglcd->recLocked == true
|| cglcd->muteLocked == true
|| cglcd->tsLocked == true
|| cglcd->ecmLocked == true
|| cglcd->timerLocked == true
|| cglcd->ddLocked == true
|| cglcd->txtLocked == true
|| cglcd->camLocked == true
|| cglcd->doShowVolume == true
|| cglcd->doMirrorOSD == true
))
{
cGLCD::getInstance()->CountDown();
}
}
return NULL;
}
void cGLCD::Run(void)
{
SNeutrinoGlcdTheme &t = g_settings.glcd_theme;
set_threadname("cGLCD::Run");
if (GLCD::Config.Load(kDefaultConfigFile) == false)
{
fprintf(stderr, "Error loading config file!\n");
return;
}
if ((GLCD::Config.driverConfigs.size() < 1))
{
fprintf(stderr, "No driver config found!\n");
return;
}
struct timespec ts;
CSectionsdClient::CurrentNextInfo info_CurrentNext;
t_channel_id epg_id = -1;
channel_id = -1;
info_CurrentNext.current_zeit.startzeit = 0;
info_CurrentNext.current_zeit.dauer = 0;
info_CurrentNext.flags = 0;
fonts_initialized = false;
bool broken = false;
do
{
if (broken)
{
#ifdef GLCD_DEBUG
fprintf(stderr, "No graphlcd display found ... sleeping for 30 seconds\n");
#endif
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += 30;
sem_timedwait(&sem, &ts);
broken = false;
if (doExit)
break;
if (!g_settings.glcd_enable)
continue;
}
else
while ((doSuspend || doStandby || !g_settings.glcd_enable) && !doExit)
sem_wait(&sem);
if (doExit)
break;
int warmUp = 10;
if ((g_settings.glcd_selected_config < 0) || (g_settings.glcd_selected_config > GetConfigSize() - 1))
g_settings.glcd_selected_config = 0;
lcd = GLCD::CreateDriver(GLCD::Config.driverConfigs[g_settings.glcd_selected_config].id, &GLCD::Config.driverConfigs[g_settings.glcd_selected_config]);
if (!lcd)
{
#ifdef GLCD_DEBUG
fprintf(stderr, "CreateDriver failed.\n");
#endif
broken = true;
continue;
}
#ifdef GLCD_DEBUG
fprintf(stderr, "CreateDriver succeeded.\n");
#endif
if (lcd->Init())
{
delete lcd;
lcd = NULL;
#ifdef GLCD_DEBUG
fprintf(stderr, "LCD init failed.\n");
#endif
broken = true;
continue;
}
#ifdef GLCD_DEBUG
fprintf(stderr, "LCD init succeeded.\n");
#endif
lcd->SetBrightness(0);
if (!bitmap)
bitmap = new GLCD::cBitmap(lcd->Width(), lcd->Height(), ColorConvert3to1(t.glcd_background_color_red, t.glcd_background_color_green, t.glcd_background_color_blue));
UpdateBrightness();
Update();
doMirrorOSD = false;
while ((!doSuspend && !doStandby) && !doExit && g_settings.glcd_enable)
{
if (doMirrorOSD && !doStandbyTime && !doStandbyWeather)
{
if (blitFlag)
{
blitFlag = false;
bitmap->Clear(GLCD::cColor::Black);
ts.tv_sec = 0; // don't wait
static CFrameBuffer *fb = CFrameBuffer::getInstance();
static int fb_height = fb->getScreenHeight(true);
static uint32_t *fbp = fb->getFrameBufferPointer();
int lcd_width = bitmap->Width();
int lcd_height = bitmap->Height();
#if BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K || BOXMODEL_VUDUO4KSE || BOXMODEL_VUULTIMO4K || BOXMODEL_VUUNO4KSE
unsigned int fb_stride = fb->getStride() / 4;
if (!showImage(fbp, fb_stride, fb_height, 0, 0, lcd_width, lcd_height, false, false))
{
#else
static int fb_width = fb->getScreenWidth(true);
if (!showImage(fbp, fb_width, fb_height, 0, 0, lcd_width, lcd_height, false, true))
{
#endif
usleep(500000);
}
else
{
lcd->SetScreen(bitmap->Data(), lcd_width, lcd_height);
lcd->Refresh(false);
}
}
else
usleep(100000);
continue;
}
if (g_settings.glcd_mirror_video && !doStandbyTime && !doStandbyWeather)
{
#if BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K || BOXMODEL_VUDUO4KSE || BOXMODEL_VUULTIMO4K || BOXMODEL_VUUNO4KSE
lcd->SetMirrorVideo(true);
#else
char ws[10];
snprintf(ws, sizeof(ws), "%d", bitmap->Width());
const char *bmpShot = "/tmp/glcd-video.bmp";
std::string grab = find_executable("grab");
if (!grab.empty())
my_system(4, grab.c_str(), "-vr", ws, bmpShot);
int bw = 0, bh = 0;
g_PicViewer->getSize(bmpShot, &bw, &bh);
if (bw > 0 && bh > 0)
{
int lcd_width = bitmap->Width();
int lcd_height = bitmap->Height();
if (!showImage(bmpShot, (uint32_t) bw, (uint32_t) bh, 0, 0, (uint32_t) lcd_width, (uint32_t) lcd_height, false, true))
usleep(1000000);
else
{
lcd->SetScreen(bitmap->Data(), lcd_width, lcd_height);
lcd->Refresh(false);
}
}
else
usleep(1000000);
continue;
#endif
}
#if BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K || BOXMODEL_VUDUO4KSE || BOXMODEL_VUULTIMO4K || BOXMODEL_VUUNO4KSE
else
lcd->SetMirrorVideo(false);
#endif
clock_gettime(CLOCK_REALTIME, &ts);
tm = localtime(&ts.tv_sec);
updateFonts();
Exec();
clock_gettime(CLOCK_REALTIME, &ts);
tm = localtime(&ts.tv_sec);
if (warmUp > 0)
{
ts.tv_sec += 1;
warmUp--;
}
else
{
ts.tv_sec += 60 - tm->tm_sec;
ts.tv_nsec = 0;
}
if (!doScrollChannel && !doScrollEpg)
sem_timedwait(&sem, &ts);
while (!sem_trywait(&sem));
if (doRescan || doSuspend || doStandby || doExit)
break;
if (doShowVolume)
{
if (ismediaplayer)
{
Channel = "";
if (Epg.compare(g_Locale->getText(LOCALE_GLCD_VOLUME)))
{
Epg = g_Locale->getText(LOCALE_GLCD_VOLUME);
EpgWidth = font_epg.Width(Epg);
doScrollEpg = EpgWidth > bitmap->Width();
scrollEpgSkip = 0;
scrollEpgForward = true;
if (doScrollEpg)
{
scrollEpgOffset = bitmap->Width() / 4;
EpgWidth += scrollEpgOffset;
}
else
scrollEpgOffset = 0;
}
ChannelWidth = 0;
scrollChannelSkip = 0;
scrollChannelForward = true;
Scale = g_settings.current_volume;
//epg_id = -1;
}
else
{
Epg = "";
if (Channel.compare(g_Locale->getText(LOCALE_GLCD_VOLUME)))
{
Channel = g_Locale->getText(LOCALE_GLCD_VOLUME);
ChannelWidth = font_channel.Width(Channel);
doScrollChannel = ChannelWidth > bitmap->Width();
scrollChannelForward = true;
scrollChannelSkip = 0;
if (doScrollChannel)
{
scrollChannelOffset = bitmap->Width() / 4;
ChannelWidth += scrollChannelOffset;
}
else
scrollChannelOffset = 0;
}
EpgWidth = 0;
scrollEpgForward = true;
scrollEpgSkip = 0;
Scale = g_settings.current_volume;
channel_id = -1;
}
}
else if (channelLocked)
{
Lock();
if (Epg.compare(stagingEpg))
{
Epg = stagingEpg;
EpgWidth = font_epg.Width(Epg);
doScrollEpg = EpgWidth > bitmap->Width();
scrollEpgForward = true;
scrollEpgSkip = 0;
if (doScrollEpg)
{
scrollEpgOffset = bitmap->Width() / 4;
EpgWidth += scrollEpgOffset;
}
else
scrollChannelOffset = 0;
}
if (Channel.compare(stagingChannel))
{
Channel = stagingChannel;
ChannelWidth = font_channel.Width(Channel);
doScrollChannel = ChannelWidth > bitmap->Width();
scrollChannelForward = true;
scrollChannelSkip = 0;
if (doScrollChannel)
{
scrollChannelOffset = bitmap->Width() / 4;
ChannelWidth += scrollChannelOffset;
}
else
scrollChannelOffset = 0;
}
channel_id = -1;
Unlock();
}
else
{
CChannelList *channelList = CNeutrinoApp::getInstance()->channelList;
if (!channelList)
continue;
t_channel_id new_channel_id = channelList->getActiveChannel_ChannelID();
if (!new_channel_id)
continue;
if ((new_channel_id != channel_id))
{
Channel = channelList->getActiveChannelName();
ChannelWidth = font_channel.Width(Channel);
epg_id = channelList->getActiveChannel()->getEpgID();
Epg = "";
EpgWidth = 0;
Scale = 0;
doScrollEpg = false;
doScrollChannel = ChannelWidth > bitmap->Width();
scrollChannelForward = true;
scrollChannelSkip = 0;
if (doScrollChannel)
{
scrollChannelOffset = bitmap->Width() / 4;
ChannelWidth += scrollChannelOffset;
}
else
scrollChannelOffset = 0;
warmUp = 10;
info_CurrentNext.current_name = "";
info_CurrentNext.current_zeit.dauer = 0;
}
CEitManager::getInstance()->getCurrentNextServiceKey(epg_id & 0xFFFFFFFFFFFFULL, info_CurrentNext);
channel_id = new_channel_id;
if (info_CurrentNext.current_name.compare(Epg))
{
Epg = info_CurrentNext.current_name;
EpgWidth = font_epg.Width(Epg);
doScrollEpg = EpgWidth > bitmap->Width();
scrollEpgForward = true;
scrollEpgSkip = 0;
if (doScrollEpg)
{
scrollEpgOffset = bitmap->Width() / 4;
EpgWidth += scrollEpgOffset;
}
else
scrollEpgOffset = 0;
}
if (info_CurrentNext.flags & CSectionsdClient::epgflags::has_current)
{
if ((info_CurrentNext.current_zeit.dauer > 0) && (info_CurrentNext.current_zeit.dauer < 86400))
{
Scale = (ts.tv_sec - info_CurrentNext.current_zeit.startzeit) * 100 / info_CurrentNext.current_zeit.dauer;
char tmp_duration[15] = {0};
int total = info_CurrentNext.current_zeit.dauer / 60;
int done = (abs(time(NULL) - info_CurrentNext.current_zeit.startzeit) + 30) / 60;
int todo = total - done;
if ((time(NULL) < info_CurrentNext.current_zeit.startzeit) && todo >= 0)
{
done = 0;
todo = info_CurrentNext.current_zeit.dauer / 60;
}
snprintf(tmp_duration, sizeof(tmp_duration), "%d/%d", done, total);
Duration = stagingDuration = tmp_duration;
}
if (Scale > 100)
Scale = 100;
else if (Scale < 0)
Scale = 0;
char tmp_start[6] = {0};
time_t tmp_start_time = info_CurrentNext.current_zeit.startzeit;
tm = localtime(&tmp_start_time);
snprintf(tmp_start, sizeof(tmp_start), "%02d:%02d", tm->tm_hour, tm->tm_min);
Start = stagingStart = tmp_start;
}
if (info_CurrentNext.flags & CSectionsdClient::epgflags::has_next)
{
char tmp_end[6] = {0};
time_t tmp_end_time = info_CurrentNext.next_zeit.startzeit;
tm = localtime(&tmp_end_time);
snprintf(tmp_end, sizeof(tmp_end), "%02d:%02d", tm->tm_hour, tm->tm_min);
End = stagingEnd = tmp_end;
}
if (Epg.empty() && (CNeutrinoApp::getInstance()->getMode() == NeutrinoModes::mode_webtv || CNeutrinoApp::getInstance()->getMode() == NeutrinoModes::mode_webradio))
{
g_InfoViewer->init_livestreamInfo();
if (g_InfoViewer->get_livestreamInfo1() == "RESOLUTION=1x1") // comes from best_bitrate_m3u8.lua
Epg = g_InfoViewer->get_livestreamInfo2();
else
Epg = g_InfoViewer->get_livestreamInfo1() + " " + g_InfoViewer->get_livestreamInfo2();
EpgWidth = font_epg.Width(Epg);
#if 0 // FIXME: scroll problem, high load
doScrollEpg = EpgWidth > bitmap->Width();
scrollEpgForward = true;
#else
doScrollEpg = false;
scrollEpgForward = false;
#endif
scrollEpgSkip = 0;
if (doScrollEpg)
{
scrollEpgOffset = bitmap->Width() / 4;
EpgWidth += scrollEpgOffset;
}
else
scrollEpgOffset = 0;
}
}
}
if (!g_settings.glcd_enable || doSuspend || doStandby)
{
// for restart, don't blacken screen
bitmap->Clear(GLCD::cColor::Black);
lcd->SetBrightness(0);
lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height());
lcd->Refresh(false);
}
if (doExit)
{
if (imageShow(DATADIR "/neutrino/icons/shutdown.jpg", 0, 0, 0, 0, false, true, true, false, false))
{
lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height());
lcd->Refresh(false);
sleep(1);
lcd->SetBrightness(0);
}
else
{
bitmap->Clear(GLCD::cColor::Black);
lcd->SetBrightness(0);
lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height());
lcd->Refresh(false);
}
return;
}
if (doRescan)
{
doRescan = false;
Update();
}
lcd->DeInit();
delete lcd;
lcd = NULL;
}
while (!doExit);
}
void cGLCD::Update()
{
if (cglcd)
{
sem_post(&cglcd->sem);
if (!cglcd->doExit)
cGLCD::getInstance()->WakeUp();
}
}
void cGLCD::StandbyMode(bool b)
{
SNeutrinoGlcdTheme &t = g_settings.glcd_theme;
if (cglcd)
{
if (t.glcd_standby_clock || t.glcd_standby_weather)
{
if (t.glcd_standby_clock)
cglcd->doStandbyTime = b;
else
cglcd->doStandbyTime = false;
if (t.glcd_standby_weather)
cglcd->doStandbyWeather = b;
else
cglcd->doStandbyWeather = false;
cglcd->doStandby = false;
}
else
cglcd->doStandby = b;
if (b)
{
cglcd->doScrollChannel = false;
cglcd->doScrollEpg = false;
}
else
{
cglcd->doScrollChannel = true;
cglcd->doScrollEpg = true;
}
cglcd->doMirrorOSD = false;
cglcd->UpdateBrightness();
cglcd->Update();
}
}
void cGLCD::ShowVolume(bool b)
{
if (cglcd)
{
cglcd->doShowVolume = b;
cglcd->Update();
}
}
void cGLCD::ShowLcdIcon(bool b)
{
if (cglcd)
{
cglcd->Lock();
cglcd->doShowLcdIcon = b;
cglcd->Unlock();
cglcd->Update();
}
}
void cGLCD::MirrorOSD(bool b)
{
if (cglcd)
{
cglcd->doMirrorOSD = b;
cglcd->Update();
}
}
void cGLCD::Exit()
{
if (cglcd)
{
cglcd->doMirrorOSD = false;
cglcd->doSuspend = false;
cglcd->time_thread_started = false;
cglcd->doExit = true;
cglcd->Update();
void *res;
pthread_join(cglcd->thrGLCD, &res);
pthread_join(cglcd->thrTimeThread, NULL);
delete cglcd;
cglcd = NULL;
}
}
void cGLCD::Respawn()
{
Exit();
cGLCD::getInstance();
}
void cGLCD::Rescan()
{
doRescan = true;
Update();
}
void cGLCD::Suspend()
{
if (cglcd)
{
cglcd->doSuspend = true;
cglcd->Update();
}
}
void cGLCD::Resume()
{
if (cglcd)
{
cglcd->doSuspend = false;
cglcd->channelLocked = false;
cglcd->Update();
}
}
void cGLCD::lockChannel(std::string c, std::string e, int s)
{
if (cglcd)
{
cglcd->Lock();
cglcd->channelLocked = true;
cglcd->stagingChannel = c;
cglcd->stagingEpg = e;
cglcd->Scale = s;
cglcd->Unlock();
cglcd->Update();
}
}
void cGLCD::unlockChannel(void)
{
if (cglcd)
{
cglcd->channelLocked = false;
cglcd->Update();
}
}
void cGLCD::lockTime(std::string t)
{
if (cglcd)
{
cglcd->Lock();
cglcd->timeLocked = true;
cglcd->stagingTime = t;
cglcd->Unlock();
cglcd->Update();
}
}
void cGLCD::unlockTime(void)
{
if (cglcd)
{
cglcd->timeLocked = false;
cglcd->Update();
}
}
void cGLCD::lockDuration(std::string t)
{
if (cglcd)
{
cglcd->Lock();
cglcd->durationLocked = true;
cglcd->stagingDuration = t;
cglcd->Unlock();
cglcd->Update();
}
}
void cGLCD::unlockDuration(void)
{
if (cglcd)
{
cglcd->durationLocked = false;
cglcd->Update();
}
}
void cGLCD::lockStart(std::string t)
{
if (cglcd)
{
cglcd->Lock();
cglcd->startLocked = true;
cglcd->stagingStart = t;
cglcd->Unlock();
cglcd->Update();
}
}
void cGLCD::unlockStart(void)
{
if (cglcd)
{
cglcd->startLocked = false;
cglcd->Update();
}
}
void cGLCD::lockEnd(std::string t)
{
if (cglcd)
{
cglcd->Lock();
cglcd->endLocked = true;
cglcd->stagingEnd = t;
cglcd->Unlock();
cglcd->Update();
}
}
void cGLCD::unlockEnd(void)
{
if (cglcd)
{
cglcd->endLocked = false;
cglcd->Update();
}
}
void cGLCD::lockIcon(int type)
{
if (cglcd)
{
cglcd->Lock();
if (type == REC)
cglcd->recLocked = true;
else if (type == MUTE)
cglcd->muteLocked = true;
else if (type == TS)
cglcd->tsLocked = true;
else if (type == ECM)
cglcd->ecmLocked = true;
else if (type == TIMER)
cglcd->timerLocked = true;
else if (type == DD)
cglcd->ddLocked = true;
else if (type == TXT)
cglcd->txtLocked = true;
else if (type == SUB)
cglcd->subLocked = true;
else if (type == CAM)
cglcd->camLocked = true;
cglcd->Unlock();
cglcd->Update();
}
}
void cGLCD::unlockIcon(int type)
{
if (cglcd)
{
if (type == REC)
cglcd->recLocked = false;
else if (type == MUTE)
cglcd->muteLocked = false;
else if (type == TS)
cglcd->tsLocked = false;
else if (type == ECM)
cglcd->ecmLocked = false;
else if (type == TIMER)
cglcd->timerLocked = false;
else if (type == DD)
cglcd->ddLocked = false;
else if (type == TXT)
cglcd->txtLocked = false;
else if (type == SUB)
cglcd->subLocked = false;
else if (type == CAM)
cglcd->camLocked = false;
cglcd->Update();
}
}
bool cGLCD::showProgressBarBorder(uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2, uint32_t scale, uint32_t color_border, uint32_t color_progress)
{
cglcd->bitmap->DrawRectangle(x1, y1, x1 + (x2 - x1 - 1), y2, color_border, false);
if (scale)
{
cglcd->bitmap->DrawRectangle(x1 + 1, y1 + 1, x1 + (scale * (x2 - x1 - 1) / 100), y2 - 1, color_progress, true);
return true;
}
else
return false;
}
bool cGLCD::showImage(fb_pixel_t *s, uint32_t sw, uint32_t sh, uint32_t dx, uint32_t dy, uint32_t dw, uint32_t dh, bool transp, bool maximize)
{
int bb_x, bb_y, bb_w, bb_h;
if (cglcd->getBoundingBox(s, sw, sh, bb_x, bb_y, bb_w, bb_h) && bb_w && bb_h)
{
if (!maximize)
{
if (bb_h * dw > bb_w * dh)
{
uint32_t dw_new = dh * bb_w / bb_h;
dx += (dw - dw_new) >> 1;
dw = dw_new;
}
else
{
uint32_t dh_new = dw * bb_h / bb_w;
dy += (dh - dh_new) >> 1;
dh = dh_new;
}
}
for (u_int y = 0; y < dh; y++)
{
for (u_int x = 0; x < dw; x++)
{
uint32_t pix = *(s + (y * bb_h / dh + bb_y) * sw + x * bb_w / dw + bb_x);
if (!transp || pix)
cglcd->bitmap->DrawPixel(x + dx, y + dy, pix);
}
}
return true;
}
return false;
}
bool cGLCD::showImage(const std::string &filename, uint32_t sw, uint32_t sh, uint32_t dx, uint32_t dy, uint32_t dw, uint32_t dh, bool transp, bool maximize)
{
bool res = false;
if (!dw || !dh)
return res;
fb_pixel_t *s = g_PicViewer->getImage(filename, sw, sh);
if (s && sw && sh)
res = showImage(s, sw, sh, dx, dy, dw, dh, transp, maximize);
if (s)
free(s);
return res;
}
bool cGLCD::showImage(uint64_t cid, std::string cname, uint32_t dx, uint32_t dy, uint32_t dw, uint32_t dh, bool transp, bool maximize)
{
std::string logo;
int sw, sh;
if (g_PicViewer->GetLogoName(cid, cname, logo, &sw, &sh, CPictureViewer::GRAPHLCD, true))
{
return showImage(logo, (uint32_t) sw, (uint32_t) sh, dx, dy, dw, dh, transp, maximize);
}
return false;
}
bool cGLCD::imageShow(const std::string &filename, uint32_t dx, uint32_t dy, uint32_t dw, uint32_t dh, bool transp, bool maximize, bool clear, bool center_sw, bool center_sh)
{
bool ret = false;
int sw, sh;
g_PicViewer->getSize(filename.c_str(), &sw, &sh);
if (sw && sh)
{
if (clear)
cglcd->bitmap->Clear(GLCD::cColor::Black);
if (maximize)
ret = showImage(filename, (uint32_t) sw, (uint32_t) sh, (uint32_t) dx, (uint32_t) dy, (uint32_t) cglcd->bitmap->Width(), (uint32_t) cglcd->bitmap->Height(), transp, false);
else if (center_sw || center_sh)
{
int move_sw = 0;
int move_sh = 0;
if (center_sw)
move_sw = dx - (sw / 2);
else
move_sw = dx;
if (center_sh)
move_sh = dy - (sh / 2);
else
move_sh = dy;
if (dw > 0 && dh > 0)
ret = showImage(filename, (uint32_t) sw, (uint32_t) sh, (uint32_t) move_sw, (uint32_t) move_sh, (uint32_t) dw, (uint32_t) dh, transp, false);
else
ret = showImage(filename, (uint32_t) sw, (uint32_t) sh, (uint32_t) move_sw, (uint32_t) move_sh, (uint32_t) sw, (uint32_t) sh, transp, false);
}
else if (dw > 0 && dh > 0)
ret = showImage(filename, (uint32_t) sw, (uint32_t) sh, (uint32_t) dx, (uint32_t) dy, (uint32_t) dw, (uint32_t) dh, transp, false);
else
ret = showImage(filename, (uint32_t) sw, (uint32_t) sh, (uint32_t) dx, (uint32_t) dy, (uint32_t) sw, (uint32_t) sh, transp, false);
}
return ret;
}
bool cGLCD::drawText(int x, int y, int xmax, int text_width, const std::string &text, const GLCD::cFont *font, uint32_t color1, uint32_t color2, bool proportional, int skipPixels, int align)
{
int z = 0;
int offset = 10; // px
if (align == ALIGN_NONE)
{
z = x;
}
else if (align == ALIGN_LEFT)
{
z = offset;
}
else if (align == ALIGN_CENTER)
{
z = std::max(offset, (bitmap->Width() - text_width) / 2);
}
else if (align == ALIGN_RIGHT)
{
z = std::max(offset, (bitmap->Width() - text_width - offset));
}
return bitmap->DrawText(z, y, xmax, text, font, color1, color2, proportional, skipPixels);
}
bool cGLCD::dumpBuffer(fb_pixel_t *s, int format, const char *filename)
{
int output_bytes = 4;
int jpg_quality = 90;
int xres = bitmap->Width();
int yres = bitmap->Height();
unsigned char *output = (unsigned char *)s;
FILE *fd = fopen(filename, "wr");
if (!fd)
return false;
if (cglcd)
cglcd->Lock();
if (format == BMP)
{
// write bmp
unsigned char hdr[14 + 40];
int i = 0;
#define PUT32(x) hdr[i++] = ((x)&0xFF); hdr[i++] = (((x)>>8)&0xFF); hdr[i++] = (((x)>>16)&0xFF); hdr[i++] = (((x)>>24)&0xFF);
#define PUT16(x) hdr[i++] = ((x)&0xFF); hdr[i++] = (((x)>>8)&0xFF);
#define PUT8(x) hdr[i++] = ((x)&0xFF);
PUT8('B');
PUT8('M');
PUT32((((xres * yres) * 3 + 3) & ~ 3) + 14 + 40);
PUT16(0);
PUT16(0);
PUT32(14 + 40);
PUT32(40);
PUT32(xres);
PUT32(yres);
PUT16(1);
PUT16(output_bytes * 8); // bits
PUT32(0);
PUT32(0);
PUT32(0);
PUT32(0);
PUT32(0);
PUT32(0);
#undef PUT32
#undef PUT16
#undef PUT8
fwrite(hdr, 1, i, fd);
int y;
for (y = yres - 1; y >= 0 ; y -= 1)
fwrite(output + (y * xres * output_bytes), xres * output_bytes, 1, fd);
}
else if (format == JPG)
{
const int row_stride = xres * output_bytes;
// write jpg
if (output_bytes == 3) // swap bgr<->rgb
{
int y;
//#pragma omp parallel for shared(output)
for (y = 0; y < yres; y++)
{
int xres1 = y * xres * 3;
int xres2 = xres1 + 2;
int x;
for (x = 0; x < xres; x++)
{
int x2 = x * 3;
SWAP(output[x2 + xres1], output[x2 + xres2]);
}
}
}
else // swap bgr<->rgb and eliminate alpha channel jpgs are always saved with 24bit without alpha channel
{
int y;
//#pragma omp parallel for shared(output)
for (y = 0; y < yres; y++)
{
unsigned char *scanline = output + (y * row_stride);
int x;
for (x = 0; x < xres; x++)
{
const int xs = x * 4;
const int xd = x * 3;
scanline[xd + 0] = scanline[xs + 2];
scanline[xd + 1] = scanline[xs + 1];
scanline[xd + 2] = scanline[xs + 0];
}
}
}
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
JSAMPROW row_pointer[1];
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, fd);
cinfo.image_width = xres;
cinfo.image_height = yres;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
cinfo.dct_method = JDCT_IFAST;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, jpg_quality, TRUE);
jpeg_start_compress(&cinfo, TRUE);
while (cinfo.next_scanline < cinfo.image_height)
{
row_pointer[0] = & output[cinfo.next_scanline * row_stride];
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
}
else if (format == PNG)
{
// write png
png_bytep *row_pointers;
png_structp png_ptr;
png_infop info_ptr;
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL);
info_ptr = png_create_info_struct(png_ptr);
png_init_io(png_ptr, fd);
row_pointers = (png_bytep *)malloc(sizeof(png_bytep) * yres);
int y;
//#pragma omp parallel for shared(output)
for (y = 0; y < yres; y++)
row_pointers[y] = output + (y * xres * output_bytes);
png_set_bgr(png_ptr);
png_set_IHDR(png_ptr, info_ptr, xres, yres, 8, ((output_bytes < 4) ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA), PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
png_set_compression_level(png_ptr, Z_BEST_SPEED);
png_write_info(png_ptr, info_ptr);
png_write_image(png_ptr, row_pointers);
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, &info_ptr);
free(row_pointers);
}
if (cglcd)
cglcd->Unlock();
fclose(fd);
return true;
}
void cGLCD::UpdateBrightness()
{
int dim_time = atoi(g_settings.glcd_brightness_dim_time.c_str());
int dim_brightness = g_settings.glcd_brightness_dim;
bool timeouted = (dim_time > 0) && (timeout_cnt == 0);
if (cglcd && cglcd->lcd)
{
if (timeouted && !cglcd->doStandbyTime && !cglcd->doStandbyWeather)
cglcd->lcd->SetBrightness((unsigned int)(dim_brightness));
else
cglcd->lcd->SetBrightness((unsigned int)((cglcd->doStandbyTime || cglcd->doStandbyWeather) ? g_settings.glcd_brightness_standby : g_settings.glcd_brightness));
}
}
void cGLCD::SetBrightness(unsigned int b)
{
if (cglcd)
cglcd->SetBrightness(b);
}
void cGLCD::TogglePower()
{
if (cglcd)
{
cglcd->power_state = 1 - cglcd->power_state;
if (cglcd->power_state)
cglcd->Resume();
else
cglcd->Suspend();
}
}
void cGLCD::Blit()
{
if (cglcd)
cglcd->blitFlag = true;
}
int cGLCD::handleMsg(const neutrino_msg_t msg, neutrino_msg_data_t /* data */)
{
if (msg == NeutrinoMessages::EVT_CURRENTNEXT_EPG)
{
Update();
return messages_return::handled;
}
return messages_return::unhandled;
}
int cGLCD::GetConfigSize()
{
return (int) GLCD::Config.driverConfigs.size();
}
std::string cGLCD::GetConfigName(int driver)
{
if ((driver < 0) || (driver > GetConfigSize() - 1))
driver = 0;
return GLCD::Config.driverConfigs[driver].name;
}
void cGLCD::AVInputMode(bool b)
{
if (cglcd)
{
bool mo = cglcd->doMirrorOSD;
if (b)
{
cglcd->doScrollChannel = false;
cglcd->doScrollEpg = false;
cglcd->MirrorOSD(false);
cglcd->lockChannel(g_info.hw_caps->boxname, g_Locale->getText(LOCALE_MAINMENU_AVINPUTMODE), 0);
}
else
{
cglcd->doScrollChannel = true;
cglcd->doScrollEpg = true;
cglcd->MirrorOSD(mo);
cglcd->unlockChannel();
}
}
}