среда, 22 августа 2012 г.

Linux. How to delete duplicate images 2?

Для создания и поддержания в актуальном виде коллекции изображений нужно иметь инструмент, позволяющий находить и удалять дубликаты. В свое время я пытался сделать такой инструмент.

Но подход, который я использовал требует значительной производительности и на больших коллекциях маленькая утилита разрастается достаточно большую программу со свое базой данных с интерфейсом и всеми прелестями программного проекта.

Более эффективно воспользоваться существующими инструментами, например мощной программой управления фотоколлекцией DigiKam.

Но штука в том, что DigiKam имеет очень мощный инструмент поиска дубликатов, не имеет возможности работы с дубликатами, кроме как мышкой и клавиатурой.

Я провел небольшое расследование и обнаружил, что результаты поиска дубликатов сохраняются в базе данных, которая обычно располагается в $HOME/Pictures/digikam4.db

Как DigiKam сохраняет результаты поиска я покажу на следующем примере.

Есть папка с изображениями.
В программе digikam запускаем поиск одинаковых изображений.

Результаты поиска сохраняются в таблице searches. Эта таблица содержит строки с результатами поиска.


Каждая строка в поле query хранит xml список содержащий id одинаковых изображений. На приведенном листинге я отформатировал xml, чтобы удобней его было читать.


 
  
   3
   2 
   1
  
 


Имена файлов изображений хранятся в таблице images и доступны по id


Путь доступен по полю (номер альбома) в таблице albums:


Путь к альбомам хранится в таблице albumroot:


Ниже пример реализации функции на bash получения пути изображения с id = 5
#!/bin/bash 

DBPATH=digikam4.db 

getPicture () 
{ 
  FILENAME=$(sqlite3 $DBPATH "SELECT name FROM images WHERE id=$1") 
  IDALBUM=$(sqlite3 $DBPATH "SELECT album FROM images WHERE id=$1") 
  REALTIVEPATH=$(sqlite3 $DBPATH "SELECT relativePath FROM albums WHERE id=$IDALBUM") 
  IDALBUMROOT=$(sqlite3 $DBPATH "SELECT albumRoot FROM albums WHERE id=$IDALBUM") 
  ROOTPATH=$(sqlite3 $DBPATH "SELECT specificPath FROM albumroots WHERE id=$IDALBUMROOT") 
  echo /home/${ROOTPATH}/${REALTIVEPATH}/${FILENAME} 
} 

FNAME=$(getPicture 5) 
echo $FNAME 

Ну, собственно, вот и венец творений.
Программа на bash, которая удаляет дубликаты изображений.
Программа удаляет дубликат меньшего размера.
Я ее успешно использую совместно с DigiKam 2.8 под Ubuntu.
Перед запуском скрипта нужно выйти из DigiKam, иначе скрипт не может получить доступ к базе, которая лочится.
#!/bin/bash
#-------------------------------------------------------------------
# Удаляет дубликаты картинок на основании поиска дубликатов в 
# программе DigiKam
#
# Проверено с DigiKam v2.8
COPYRUGHT="\n© http://axa-ru.blogspot.com. Licensed under GPLv3."

#-------------------------------------------------------------------
#VERSION=0.1 # initial version
#VERSION=0.11 # Some DeBugs
#VERSION=0.12 # Добавлено приоритет удаления
#VERSION=0.13 # Some changes
VERSION=0.14 # Испрвавление ошибки в delSmallPic()

DEBUG=0
VERBOSE=1
DBPATH=$HOME/Pictures/digikam4.db # Путь до базы даннх DigiKam
EXITERROR=192

SAVEPIC=""
PATTERN=0_WallPapers99

# Color ANSY sequence
BLACK="\033[0;30m"
RED="\033[0;31m"
GREEN="\033[0;32m"
YELLOW="\033[0;33m"
BLUE="\033[0;34m"
MAGENTA="\033[0;35m"
CYAN="\033[0;36m"
WHITE="\033[0;37m"
GRAY1="\033[38;5;252m"
GRAY2="\033[38;5;245m"
GRAY3="\033[38;5;238m"
NOCOLOR="\033[0;38m"

#-------------------------------------------------------------------
#  Возвращает по id изображения его полный путь
#  пример использования:
#     FNAME=$(getPicture 1653)
#  возвращает путь к картинке №1653

getPicture ()
{
  FILENAME=$(sqlite3 $DBPATH "SELECT name FROM images WHERE id=$1")
  IDALBUM=$(sqlite3 $DBPATH "SELECT album FROM images WHERE id=$1")
  REALTIVEPATH=$(sqlite3 $DBPATH "SELECT relativePath FROM albums WHERE id=$IDALBUM")
  IDALBUMROOT=$(sqlite3 $DBPATH "SELECT albumRoot FROM albums WHERE id=$IDALBUM")
  local ALBUM_TYPE=$(sqlite3 $DBPATH "SELECT type FROM albumroots WHERE id=$IDALBUMROOT")
  case $ALBUM_TYPE in
    1) ROOTPATH=/home$(sqlite3 $DBPATH "SELECT specificPath FROM albumroots WHERE id=$IDALBUMROOT");;
    2) echo "External media not supported yet. Exiting"; exit $EXITERROR;;
    3) ROOTPATH=$(sqlite3 $DBPATH "SELECT identifier FROM albumroots WHERE id=$IDALBUMROOT" | sed 's/networkshareid:?mountpath=//g' | sed 's/%2F/\//g');;
  esac  

  echo ${ROOTPATH}/${REALTIVEPATH}/${FILENAME}
}

#-------------------------------------------------------------------
#  Удаляет меньшую картинку из двух
#  
delSmallPic()
{
  ((DEBUG)) && echo "    ***** $FUNCNAME"

  if [ "$SAVEPIC" == "" ]; then 
    #((DEBUG)) && echo "    $LINENO: Init SAVEPIC"
    SAVEPIC="$1";
  else
    local W0=$(identify -format '%w' "$SAVEPIC" 2> /dev/null)
    local H0=$(identify -format '%h' "$SAVEPIC" 2> /dev/null)
    local W1=$(identify -format '%w' "$1" 2> /dev/null)
    local H1=$(identify -format '%h' "$1" 2> /dev/null)

    ((DEBUG)) && echo "    $LINENO: PIC1=$SAVEPIC"
    ((DEBUG)) && echo "    $LINENO: PIC2=$1"
    ((DEBUG)) && echo "    $LINENO: $W0 -eq $W1 -a $H0 -eq $H1"

    # Если картинки одинаковы то удаляет ту, в пути (имени)
    # которой есть $PATTERN
    if [ $W0 -eq $W1 -a $H0 -eq $H1 ]; then
      ((DEBUG)) && echo "    $LINENO: PIC1 == PIC2"
      if [[ "$SAVEPIC" =~ .*$PATTERN.* ]]; then
        echo "Delete $SAVEPIC"
        ((DEBUG)) && printf "    %s: " $LINENO
        ! ((DEBUG)) && rm "$SAVEPIC"
        SAVEPIC="$1"
      else
        ((DEBUG)) && printf "    %s: " $LINENO
        echo "Delete $1"
        ! ((DEBUG)) && rm "$1"
      fi
    else 
      if [ $W0 -le $W1 -o $H0 -le $H1 ]; then
        ((DEBUG)) && echo "    $LINENO: PIC1 <= PIC2"
        echo "Delete $SAVEPIC"
        ((DEBUG)) && printf "    %s: " $LINENO
        ! ((DEBUG)) && rm "$SAVEPIC"
        SAVEPIC="$1"
      else
        ((DEBUG)) && echo "    $LINENO: PIC1 > PIC2"
        ((DEBUG)) && printf "    %s: " $LINENO
        echo "Delete $1"
        ! ((DEBUG)) && rm "$1"
      fi    
    fi
  fi
}

#-------------------------------------------------------------------
#  Удаляет дубликаты картинок из списка
#  В качестве параметра получает список id картинок с разделителями пробелами
delDupPic ()
{
  while (( "$#" )); do
    local PAR=$1
    PICURL=$(getPicture "$PAR")
    if [ ! -f $PICURL ]; then
      echo -e "${RED}File $PICURL das not exists.${NOCOLOR}"
      # echo -e "${RED}Use digiKam!!!${NOCOLOR}"
      # exit $EXITERROR
    fi
    ((DEBUG)) && echo "  $LINENO: PAR=$PAR, PICURL=$PICURL"
    delSmallPic $PICURL
    shift
  done
}

#-------------------------------------------------------------------
#  main code
#

  while getopts "Dd:hVv" SWITCH ; do
    case $SWITCH in
      D) DEBUG=1;;
      d) if [[ $OPTARG == "" ]]; then 
           printf "$SCRIPT:$LINENO: must be argument\n"; 
           exit $ERROR; 
         else 
           PATTERN=$OPTARG; 
         fi;;
      h) echo -e "usage: 
  ${CYAN}$0 [-OPTION]${NOCOLOR}

    OPTION is
    ${CYAN}D${NOCOLOR}       - Debug On
    ${CYAN}d [PAT]${NOCOLOR} - Delete first pic by PATtern
                Example: 
                 deldup.sh -d 00_Picture 
                will delete any picture
                 /mnt/nas3d0/Pictures/Wallpaper/00_Pictures/Pictures_0123.jpg 
    ${CYAN}h${NOCOLOR}       - This help
    ${CYAN}v${NOCOLOR}       - Verbose output, No output by default"
        exit 0
        ;;
      V) echo -e "${CYAN}$0 Version $VERSION\n${COPYRUGHT}${NOCOLOR}"; exit 0;;
      v) VERBOSE=1;;
      *) printf "$SCRIPT:$LINENO: script error: unhandled argument\n"; exit $ERROR;;
    esac
  done


((DEBUG)) && echo "$LINENO: TOTAL=$TOTAL"

# Type=7 - записи после операции поиска дубликатов
X=$(sqlite3 $DBPATH "SELECT id FROM searches where type=7 LIMIT 1")
TOTAL=$(sqlite3 $DBPATH "SELECT COUNT (*) FROM searches WHERE type=7")
echo "$TOTAL Duplicate Images Will be Delete "
((LAST=TOTAL+X))
((DEBUG)) && echo "$LINENO: X=$X, LAST=$LAST, TOTAL=$TOTAL"

while [ $X -lt $LAST ]
do
  SAVEPIC=""
  # Получаем список записей с дублированными картинками 
  # Ниже показан отформатированный пример. 
  # 
  # 
  #   
  #     
  #       5033
  #       201
  #       84132
  #     
  #   
  # 
  LISTEQPIC=$(sqlite3 $DBPATH "SELECT query FROM searches WHERE id=$X" | sed 's/<\/listitem>/,/g' | sed 's///g' | sed 's/.*oneof\">//' | sed 's/,<\/.*//' | sed 's/,/ /g' )
  ((DEBUG)) && echo "$LINENO: X=$X, LISTEQPIC=$LISTEQPIC"
  delDupPic $LISTEQPIC
  ((X++))
done

По хорошему этот скрипт можно оформить в виде плагина в DigiKam и запускать оттуда. Будет функциональней и удобней. Но мне лень ковырять сам DigiKam. Если кто сделает такое добро, то отпишите.


Полезные ссылки:

воскресенье, 12 августа 2012 г.

Corbina (beeline) radio.

В последнее время эффективные менеджеры beeline монетизируют все, что можно и все, что нельзя.
А что не получается монетизировать, то им не интересно.
Похоже, что эффективным менеджерам из билайн до лампочки интернет радио, доставшееся от Корбины.
Какое то радио работает, но полного списка станций я не нашел.

Для поиска работающих радиостанций я написал простенький скрипт на bash:
#!/bin/bash

PORT=8000

while [ $PORT -lt 10000 ]; do
   printf "\r%s  " "$PORT"
   RESULT=$(mplayer -frames 0  http://radio.corbina.ru:$PORT/ 2>/dev/null | grep playback)
   if [ "$RESULT" == "Starting playback..." ]
   then 
      NAME=$(mplayer -frames 0  http://radio.corbina.ru:$PORT/ 2>/dev/null | grep Name)
      echo -e "\rhttp://radio.corbina.ru:$PORT   $NAME"
   fi
   ((PORT++))
done
Запустив его в консоли через пару минут мы получаем все работающие станции в диапазоне портов от 8000 до 10000:
http://radio.corbina.ru:8000 Name : (GTM) CorBinA PsychedeliC StaTioN http://radio.corbina.ru:8005 Name : POP CorBinA RaDiO StatioN http://radio.corbina.ru:8010 Name : Corbina Dark & Metal Radio http://radio.corbina.ru:8015 Name : DruM and BasS CorBinA RaDiO StatioN http://radio.corbina.ru:8025 Name : (GTM) HousE CorBinA RaDiO StatioN http://radio.corbina.ru:8030 Name : BriT CorBinA RaDiO StatioN http://radio.corbina.ru:8035 Name : (GTM) AmbienT CorBinA RaDiO StatioN http://radio.corbina.ru:8040 Name : Deep Mix Moscow Radio: deepmix.ru http://radio.corbina.ru:8050 Name : EuroHIT CorBinA RaDiO StatioN http://radio.corbina.ru:8067 Name : ShaNsoN CorBinA RaDiO StatioN http://radio.corbina.ru:8071 Name : RagnaroK CorBinA RaDiO StatioN http://radio.corbina.ru:8073 Name : RocK-Ru CorBinA RaDiO StatioN http://radio.corbina.ru:8107 Name : Heavy Music Atmospheric Radio http://radio.corbina.ru:9040 Name : Deep Mix Moscow Radio: deepmix.ru http://radio.corbina.ru:9045 Name : Deep Mix Moscow Radio: deepmix.ru http://radio.corbina.ru:9054 Name : Corbina Radio: Big Beat radio (HighQuality) http://radio.corbina.ru:9056 Name : Corbina Radio: BigBeat Radio

суббота, 11 августа 2012 г.

Ссылки по Qt

Документация

Форумы


Блоги, статьи


Книги, tutorials, примеры

How to delete old kernels

Очень просто.
Я сохранил скрипт под именем del_old_kernels.sh

#!/bin/bash 
for K in $(ls /boot/ | grep vmlinuz | sed 's@vmlinuz-@linux-image-@g' | grep -v `uname -r`)
do
  aptitude remove $K
done
update-grub
Затем дал права скрипту на исполнение, установил aptitude и запустил скрипт.

chmod +x del_old_kernels.sh sudo apt-get install aptitude sudo ./del_old_kernels.sh

Полезные ссылки:

среда, 4 июля 2012 г.

Утренний бред МТС

МТС > Здравствуйте!
Чем я могу Вам помочь?

User > Доброе утро.
Вопрос. В связи с тем, что прямые городские номера отменены, будет ли снижение стоимости тарифа Maxi plus (с прямым городским номером)?

МТС > Стоимость оказания услуг останется прежней.

User > Могу я сменить тариф и оставить тот же номер?

МТС > К сожалению, при смене тарифного плана не поддерживающий предоставление городского номера, текущий номер будет изменен полностью. Смена тарифного плана в данном случае возможна только в салоне-магазине МТС.

User > Ок. В свете предыдущего вопроса: что такое "городской номер"?

МТС > Городской номер набирается как начиная с 985, так и с 495.

User > Понятно. Бред.

МТС > Уточните, пожалуйста, у Вас есть ещё какие-либо вопросы? Спасибо за обращение. Вы можете закрыть окно или ещё раз воспользоваться on-line консультацией.

воскресенье, 3 июня 2012 г.

Шрифты Win7 в Ubuntu

Тема избитая, но все таки. Сегодня с ней столкнулся и потратил час, чтобы настроить.

Чтобы в пакетах LibreOffice тексты отображались так же как и в MS Office нужно, как минимум, установить шрифты от windows идущие в стандартной поставке.
Кроме того в Ubuntu стоят маловостребованные на территории России китайские, малайские и иже с ними шрифты.

Я удалил китайские-малайские шрифты:
sudo apt-get remove ttf-indic-fonts-core ttf-kacst-one ttf-khmeros-core ttf-lao ttf-punjabi-fonts ttf-takao-pgothic ttf-thai-tlwg ttf-unfonts-core ttf-wqy-microhei fonts-kacst fonts-kacst-one fonts-khmeros-core fonts-lao fonts-takao-pgothic fonts-thai-tlwg fonts-tlwg-garuda fonts-tlwg-kinnari fonts-tlwg-loma fonts-tlwg-mono fonts-tlwg-norasi fonts-tlwg-purisa fonts-tlwg-sawasdee fonts-tlwg-typewriter fonts-tlwg-typist fonts-tlwg-typo fonts-tlwg-umpush fonts-tlwg-waree fonts-nanum
Затем удалил неполные пакеты шрифтов: sudo apt-get remove ttf-dejavu-core ttf-dejavu-extra fonts-liberation ttf-liberation
Затем скачал и установил пакет с русскими шрифтами от Windows 7: cd /tmp wget https://www.opendrive.com/files/57831796_SiIyc_8fa4/win7-rus-fonts_0.0.10_all.deb sudo dpkg -i win7-rus-fonts_0.0.10_all.deb
Вуаля, а ни какая не виола.

четверг, 24 мая 2012 г.

Следи за базаром.

Я вчера сильно прокололся.

Но все по порядку. Сейчас я веду очень крупный проект.
Набивается ко мне на встречу одна девица из конкурирующей компании. Говорит типа давайте мол пообщаемся и мы вам поможем. Ну, думаю, давайте. В конце концов проект очень большой, и места всем хватит.
Приехали двое, сели у меня и давай на ноутах за мной стенографировать. Я смотрю на них и думаю, что вы мол делать хотите? Помогать или нас выдавливать из проекта?

Порасказывал им немного и предлагаю подписать NDA (договор о неразглашении). Они покивали, типа да-да и сразу начнем.

Потом я пару тройку дней их помариновал и вчера отсылаю проект NDA. Стандартный такой. Ничего суперспециального. В ответ приходит письмо, типа я думала, что вы человека дадите и они согласуют мол с моим челом этот гребаный NDA. Я аж подпрыгнул. Да-а-а, если мы формальные бумажки так согласовывать будем, то какая к черту совместная работа...

Я пишу коллеге, смотри мол, какие перцы. Ну здесь я допустил ошибку и написал "ох****** рожа". В общем матом написал.

И в запарке отправил это девице из конкурирующей фирмы.

Она там прочитала и тоже подпрыгнула. И пишет в ответ. Типа, мол, я тоже похохотала, но какие претензии? Даже думать не стала, что да как.

Ну а дальше эта .... она пишет своему генеральному и прикладывает переписку. Тот звонит владельцу моей копании и говорит, мол у тебя перец в неадеквате всех посылает в пешее путешествие...

В общем вчера был веселый день.

Вот сейчас пишу этот пост и думаю:
То что я не прав - это стопудово. Сейчас напечатаю плакат "Следи за базаром" и наклею на стенку перед своей рожей.
Но какой профит получила девица?
Будут они в проекте дальше или нет?
И как себя вести адекватно, если в твой адрес приходит случайно чья то внутренняя почта с не очень толерантными высказываниями?

Вот такой юмор.
Друзья, попинайте меня ногами и выскажите свое видение ситуации.

среда, 28 марта 2012 г.

QML. Первое приложение для Nokia N9.

Как и обещал ранее в целях изучения я написал маленькое приложение на QML.
Я прочитал на хабре статью Как легко творить прекрасное и взял код из этой статьи за основу.
Была задача на сделать законченное приложение показывающее картинки из интернета и имеющее элементы управления.
"Прекрасное" с хабрахабра дало мне дополнительные силы и заставляло концентрироваться на документации.

Вот что из этого получилось.


Вся программа составляет примерно 290 срок.
Можно скопировать ее отсюда и вставить в новый проект Qt Creator, заменив содержимое main.qml

import QtQuick 1.1
import com.nokia.meego 1.0

Window {
    id: mainWnd
    width: 480
    height: 854

    property real interVal: 5000
    property int y1: 0
    property int y2: 0

    function getPictureURL(){
        var str = '' + Math.round(Math.random() * 5055);
        while (str.length < 5) {
            str = '0' + str;
        }
        var url = "http://media.oboobs.ru/boobs/"+ str + ".jpg";
        return url;
    }

    state: (screen.currentOrientation === Screen.Portrait) ? "portrait" : "landscape"

    states: [
        State {
            name: "landscape"
            PropertyChanges { target: aRectStatMsg; width: 814}

            PropertyChanges { target: aRectChangeDealy; x: 20}
            PropertyChanges { target: aRectChangeDealy; y: 80}
            PropertyChanges { target: aRectChangeDealy; width: 550}
            PropertyChanges { target: aRectChangeDealy; height: 380}

            PropertyChanges { target: aRectReloadPic; x: 590}
            PropertyChanges { target: aRectReloadPic; y: 80}
            PropertyChanges { target: aRectReloadPic; width: 244}
            PropertyChanges { target: aRectReloadPic; height: 180}

            PropertyChanges { target: aRectPausePic; x: 590}
            PropertyChanges { target: aRectPausePic; y: 280}
            PropertyChanges { target: aRectPausePic; width: 244}
            PropertyChanges { target: aRectPausePic; height: 180}

            PropertyChanges { target: arrow_uppng; anchors.topMargin: 33}
            PropertyChanges { target: arrow_downpng; anchors.bottomMargin: 33}
        },
        State {
            name: "portrait"
            PropertyChanges { target: aRectStatMsg; width: 440}

            PropertyChanges { target: aRectChangeDealy; x: 20}
            PropertyChanges { target: aRectChangeDealy; y: 80}
            PropertyChanges { target: aRectChangeDealy; width: 260}
            PropertyChanges { target: aRectChangeDealy; height: 740}

            PropertyChanges { target: aRectReloadPic; x: 300}
            PropertyChanges { target: aRectReloadPic; y: 80}
            PropertyChanges { target: aRectReloadPic; width: 160}
            PropertyChanges { target: aRectReloadPic; height: 362}

            PropertyChanges { target: aRectPausePic; x: 300}
            PropertyChanges { target: aRectPausePic; y: 457}
            PropertyChanges { target: aRectPausePic; width: 160}
            PropertyChanges { target: aRectPausePic; height: 363}

            PropertyChanges { target: arrow_uppng; anchors.topMargin: 80}
            PropertyChanges { target: arrow_downpng; anchors.bottomMargin: 80}
        }
    ]


    Image {
        id: image1
        opacity: 1
        fillMode: Image.PreserveAspectFit
        anchors.fill: parent
        source: ""
        onStatusChanged: if (status === Image.Error) source = getPictureURL()
    }

    Timer {
        id: myTimer
        interval: mainWnd.interVal
        running: true
        repeat: true
        onTriggered: image1.source = getPictureURL()
    }

    Rectangle {
        id: layerControl
        anchors.fill: parent
        color: "transparent"
        opacity: 0.4
        radius: 10
        property bool activOpacity: false

        states:[
            State {
                name: "showOn"; when: layerControl.activOpacity === true
                PropertyChanges { target: layerControl; opacity: 0.7; }
            },
            State {
                name: "showOff"; when: layerControl.activOpacity === false
                PropertyChanges { target: layerControl; opacity: 0.01 }
            }
        ]

        transitions: [
            Transition {
                from: "showOff"; to: "showOn";
                NumberAnimation { properties: "opacity"; duration: 100 }
            },

            Transition {
                from: "showOn"; to: "showOff";
                NumberAnimation { properties: "opacity"; duration: 1000 }
            }
        ]

        Rectangle {
            id: aRectStatMsg
            x: 20
            y: 20
            width: 440
            height: 40
            radius: parent.radius
            color: "steelblue"

            Text {
                id: actionDescription
                x: 10
                font.family: "Helvetica"
                font.bold: true
                font.pixelSize: 32
                color: "#35bcff"
                text: ""
             }
        }

        Rectangle {
            id: aRectChangeDealy
            x: 20
            y: 80
            width: 260
            height: 740
            radius: parent.radius
            color: "steelblue"

            MouseArea {
                anchors.fill: parent

                onPositionChanged: {
                    mainWnd.y1 = mainWnd.y2
                    mainWnd.y2 = mouseY
                    if ((mainWnd.y2 - mainWnd.y1) > 0)
                        mainWnd.interVal += 100
                    else
                        mainWnd.interVal -= 100
                    if ( mainWnd.interVal < 1000)
                        mainWnd.interVal = 1000
                    actionDescription.text = "SlideShow Timeout = " + Math.round(mainWnd.interVal / 1000)  + "sec"
                    console.log("PositionChanged: " + mainWnd.y1 + ", " + mainWnd.y2)
                }
                onPressed: {
                    layerControl.activOpacity = true
                    console.log("aRectChangeDealy pressed")
                }
                onReleased: {
                    layerControl.activOpacity = false
                    console.log("aRectChangeDealy released")
                }
            }

            Image {
                id: arrow_uppng
                anchors.horizontalCenter: aRectChangeDealy.horizontalCenter
                anchors.top: aRectChangeDealy.top
                anchors.topMargin: 80
//                y: 80
                source: "arrow_up.png"
                MouseArea {
                    anchors.fill: parent

                    onPressed: {
                        mainWnd.interVal -= 1000
                        if ( mainWnd.interVal < 1000)
                            mainWnd.interVal = 1000
                        actionDescription.text = "SlideShow Timeout = " + Math.round(mainWnd.interVal / 1000)  + "sec"
                        layerControl.activOpacity = true
                        console.log("arrow_uppng pressed")
                    }
                    onReleased: {
                        layerControl.activOpacity = false
                        console.log("arrow_uppng released")
                    }
                }
            }

            Image {
                id: arrow_downpng
                anchors.horizontalCenter: aRectChangeDealy.horizontalCenter
                anchors.bottom: aRectChangeDealy.bottom
                anchors.bottomMargin: 80
//                y: 532
                source: "arrow_down.png"
                MouseArea {
                    anchors.fill: parent

                    onPressed: {
                        mainWnd.interVal += 1000
                        actionDescription.text = "SlideShow Timeout = " + Math.round(mainWnd.interVal / 1000)  + "sec"
                        layerControl.activOpacity = true
                        console.log("arrow_downpng pressed")
                    }
                    onReleased: {
                        layerControl.activOpacity = false
                        console.log("arrow_downpng released")
                    }
                }
            }

        }

        Rectangle {
            id: aRectReloadPic
            x: 300
            y: 80
            width: 160
            height: 362
            radius: parent.radius
            color: "steelblue"
            Image {
                anchors.horizontalCenter: aRectReloadPic.horizontalCenter
                anchors.verticalCenter: aRectReloadPic.verticalCenter
                id: repeatpng
                source: "repeat.png"
            }

            MouseArea {
                anchors.fill: parent

                onPressed: {
                    image1.source = getPictureURL()
                    myTimer.restart()
                    actionDescription.text = "Loading next picture"
                    layerControl.activOpacity = true
                    console.log("aRectReloadPic pressed")
                    if (image1.status == Image.Error) console.log('Ошибка загрузки картинки')
                }
                onReleased: {
                    layerControl.activOpacity = false
                    console.log("aRectReloadPic released")
                }
            }
        }

        Rectangle {
            id: aRectPausePic
            x: 300
            y: 457
            width: 160
            height: 363
            radius: parent.radius
            color: "steelblue"
            Image {
                anchors.horizontalCenter: aRectPausePic.horizontalCenter
                anchors.verticalCenter: aRectPausePic.verticalCenter
                id: pausepng
                source: "pause.png"
            }
            MouseArea {
                anchors.fill: parent

                onPressed: {
                    myTimer.stop()
                    actionDescription.text = "SlideShow stoped"
                    layerControl.activOpacity = true
                    console.log("aRectPausePic pressed")
                }
                onReleased: {
                    layerControl.activOpacity = false
                    console.log("aRectPausePic released")
                }
            }
        }
    }
}
Скомпилированное приложение можно скачать по этой ссылке: slideshow_0.1.1_armel.deb
Полностью проект (tarball) можно скачать по это1 ссылке: bobshow_v0.1.1.tar.gz

вторник, 6 марта 2012 г.

Nokia N9. Мод экрана вызова.

Последнее обновление прошивки PR1.3 для Nokia N9 дало по утверждению разработчиков более 1000 обновлений и полезных функций.
Одновременно поменялись таблицы стилей, описывающие вид выводимых экранов.
По этой причине мод, изменяющий размер аватары, сделанный для прошивки PR1.1 и PR1.2 не подходит для PR1.3.

Я сделал собственный мод, который увеличивает аватар и размер клавиш "снять трубку" и "отбой".

//Including the carmode styles of call-ui
@import "carmode-call-ui.css" // * Plugs the carmode styles for callui *
/*
    NOTE:
        Telephony layout guide was built using 35px status bar.
        Here we assume using the whole page height (screen height -status bar)
        and add the -1px correction into any value relative to available screen
        height.
*/

// ***************************************************************************
// ** CONSTANTS **************************************************************

// ** screen (page) dimensions **
@const PAGE_HEIGHT                     : 818px; // == full height (854px) - $HEIGHT_STATUSBAR (36px)
@const PAGE_WIDTH                      : 480px; // == full width (480px)

@const PAGE_HEIGHT_LS                  : 444px; // == full height (480px) - $HEIGHT_STATUSBAR (36px)
@const PAGE_WIDTH_FULL_LS              : 854px;

// ** CallWidget **
@const CALLWIDGET_SIZE                 : $PAGE_WIDTH 544px;
@const CALLWIDGET_SIZE_MINIMIZED       : $PAGE_WIDTH 64px;
@const CALLWIDGET_SIZE_VIDEO           : $PAGE_WIDTH_FULL_LS $PAGE_HEIGHT_LS;
@const CALLWIDGET_SIZE_VIDEO_MINIMIZED : $PAGE_WIDTH_FULL_LS 64px;
@const CALLWIDGET_SIZE_VIDEO_MAXIMIZED : $PAGE_WIDTH 380px; // PAGE_HEIGHT_LS - 64

// ** Avatar **
//@const AVATAR_SIZE               : 64px 64px;
@const AVATAR_SIZE               : 256px 256px;

// ** InfoPanel **
@const CALLINFO_SIZE_NORMAL             : $PAGE_WIDTH 124px;
@const CALLINFO_SIZE_NORMAL_MAX         : $PAGE_WIDTH    -1;
@const CALLINFO_SIZE_MINIMIZED          : $PAGE_WIDTH  64px;
@const CALLINFO_SIZE_VIDEO              : 592px 85px;
@const CALLINFO_SIZE_VIDEOPAGE_INCOMING     : $PAGE_WIDTH 124px; // FIXME: random value
@const CALLINFO_SIZE_VIDEOPAGE_INCOMING_MAX : $PAGE_WIDTH    -1; // FIXME: random value



// ***************************************************************************
// ** Window overrides *******************************************************

MWindowStyle {
    x11-startup-pixmap:;
    startup-fill-color: #000000;
}

MWindowStyle.Portrait {
    x11-startup-pixmap:;
    startup-fill-color: #000000;
}

MWindowStyle.Landscape {
    x11-startup-pixmap:;
    startup-fill-color: #000000;
}

MApplicationWindowStyle#DisabledStatusMenu {
    status-bar-style-name: "CommonStatusBarNoMenu";
}


// ***************************************************************************
// ** Container (application page) *******************************************

#CallApplicationPage {
    offset           : 0 0;

    minimum-size     : 100% 100%;
    preferred-size   : 100% 100%;
    maximum-size     : 100% 100%;

    margin-left      : 0;
    margin-right     : 0;
    margin-top       : 0;
    margin-bottom    : 0;

    padding-left     : 0;
    padding-right    : 0;
    padding-top      : 0;
    padding-bottom   : 0;

    background-color : #000000;

    background-image :;
}


// ***************************************************************************
// ** CallAvatar *************************************************************

#CallAvatar {
    margin-left      : 0;
    margin-right     : 0;
    margin-top       : 0;
    margin-bottom    : 0;

    padding-left     : 0;
    padding-right    : 0;
    padding-top      : 0;
    padding-bottom   : 0;

    preferred-size   : -1 -1;
    minimum-size     : -1 -1;
    maximum-size     : -1 -1;

    background-color :;
    background-image :;

    press-feedback   :;
    release-feedback :;
    cancel-feedback  :;
}

#CallAvatar:pressed {
    background-color :;
    background-image :;
}

#CallAvatarImage {
    margin-left    : 100;  //  Определено эмпирически
    margin-right   : -356; // -100-256 (-(margin-left)-$AVATAR_SIZE)
    margin-top     : -276; // -20-256 (-(margin-bottom)-$AVATAR_SIZE)
    margin-bottom  : 20;  // Бля! Почему "+"?

    padding-left   : 0;
    padding-right  : 0;
    padding-top    : 0;
    padding-bottom : 0;

    preferred-size : $AVATAR_SIZE;
    minimum-size   : $AVATAR_SIZE;
    maximum-size   : $AVATAR_SIZE;
}

#ConfCallAvatarButton {
    background-image   : meegotouch-callui-button-shadowed-background $CORNER_MARGINS;
    background-color   :;
    text-color         :;

    padding-left       : 0;
    padding-top        : 0;
    padding-right      : 0;
    padding-bottom     : 0;

    icon-size          : 40px 40px;
    icon-align         : center;

    margin-left        : 0;
    margin-top         : 0;
    margin-right       : 0;
    margin-bottom      : 0;

    text-margin-left   : 0;
    text-margin-top    : 0;
    text-margin-right  : 0;
    text-margin-bottom : 0;

    preferred-size     : $AVATAR_SIZE;
    minimum-size       : $AVATAR_SIZE;
    maximum-size       : $AVATAR_SIZE;

    press-feedback     :;
    release-feedback   :;
}

#ConfCallAvatarButton:pressed {
    background-image   : meegotouch-callui-button-shadowed-background-pressed $CORNER_MARGINS;
    background-color   :;
}


// ***************************************************************************
// ** CallInfoPanel **********************************************************

CallInfoPanelStyle {
    margin-left      : 0;
    margin-right     : 0;
    margin-top       : 0;
    margin-bottom    : 0;

    padding-left     : $MARGIN_XLARGE;
    padding-right    : $MARGIN_XLARGE;
    padding-top      : 8px;
    padding-bottom   : 0px;

    background-image :;
    background-color :;

    press-feedback   :;
    release-feedback :;
    cancel-feedback  :;
}

#CallInfoPanel_Normal {
    minimum-size   : $CALLINFO_SIZE_NORMAL;
    maximum-size   : $CALLINFO_SIZE_NORMAL_MAX;
    preferred-size : $CALLINFO_SIZE_NORMAL_MAX;
}

#CallInfoPanel_Minimized {
    padding-top    : 0;

    minimum-size   : $CALLINFO_SIZE_MINIMIZED;
    maximum-size   : $CALLINFO_SIZE_MINIMIZED;
    preferred-size : $CALLINFO_SIZE_MINIMIZED;
}

#CallInfoPanel_Video {
    minimum-size       : $CALLINFO_SIZE_VIDEO;
    maximum-size       : $CALLINFO_SIZE_VIDEO;
    preferred-size     : $CALLINFO_SIZE_VIDEO;

    padding-left       : 0px;

    background-color   : #000000;
    background-opacity : 0.30;
}

#CallInfoPanel_VideoPage_Incoming {
    minimum-size   : $CALLINFO_SIZE_VIDEOPAGE_INCOMING;
    maximum-size   : $CALLINFO_SIZE_VIDEOPAGE_INCOMING_MAX;
    preferred-size : $CALLINFO_SIZE_VIDEOPAGE_INCOMING_MAX;

    // FIXME: hack for pushing buttons down a bit to workaround some
    // serious insanity with MGridLayoutPolicy
    //margin-bottom  : 72px;
}


// ***************************************************************************
// ** Buttons ****************************************************************

MButtonStyle:disabled {
    background-image : none;
    background-color : none;
    text-color       : none;
}

MButtonStyle:disabled-selected {
    background-image : none;
    background-image : none;
    text-color       : none;
}


#CallUi_EndButton {
    background-image : meegotouch-callui-button-reject-background $CORNER_MARGINS;

    preferred-size   : 210px 64px;
    minimum-size     : 210px 64px;
    maximum-size     : 210px 64px;

    icon-align       : center;
    icon-size        : 48px 48px;

    press-feedback   : priority2_callbutton_press;
    release-feedback : priority2_callbutton_release;
    cancel-feedback  :;

    margin-left      : 0;
    margin-right     : 0;
    margin-top       : 0;
    margin-bottom    : 0;

    padding-left     : 0;
    padding-right    : 0;
    padding-top      : 0;
    padding-bottom   : 0;
}

#CallUi_EndButton:pressed {
    background-image : meegotouch-callui-button-reject-background-pressed $CORNER_MARGINS;
}

#CallUi_EndButton_Video {
    background-image : meegotouch-callui-button-reject-background $CORNER_MARGINS;

    preferred-size   : 230px 64px;
    minimum-size     : 230px 64px;
    maximum-size     : 230px 64px;

    icon-align       : center;
    icon-size        : 48px 48px;

    press-feedback   : priority2_callbutton_press;
    release-feedback : priority2_callbutton_release;
    cancel-feedback  :;

    margin-left      : $MARGIN_XLARGE;
    margin-right     : $MARGIN_XLARGE;
    margin-top       : $MARGIN_XLARGE;
    margin-bottom    : $MARGIN_XLARGE;

    padding-left     : 0;
    padding-right    : 0;
    padding-top      : 0;
    padding-bottom   : 0;
}

#CallUi_EndButton_Video:pressed {
    background-image : meegotouch-callui-button-reject-background-pressed $CORNER_MARGINS;
}

// Кнопка Redial 8)
#CallUi_RedialButton {
    background-image : meegotouch-callui-button-answer-background $CORNER_MARGINS;

    preferred-size   : 210px 128px;
    minimum-size     : 210px 128px;
    maximum-size     : 210px 128px;
//    preferred-size   : 210px 64px;
//    minimum-size     : 210px 64px;
//    maximum-size     : 210px 64px;

    icon-id          :;

    press-feedback   : priority2_callbutton_press;
    release-feedback : priority2_callbutton_release;
    cancel-feedback  :;

    font             : $FONT_FAMILY bold uppercase 2.2mm ;//22px
    text-color       : #F5F5F5;

    margin-left      : 0;
    margin-right     : 0;
    margin-top       : 0;
    margin-bottom    : 24px;

    padding-left     : 0;
    padding-right    : 0;
    padding-top      : 0;
    padding-bottom   : 0;
}

#CallUi_RedialButton:pressed {
    background-image : meegotouch-callui-button-answer-background-pressed $CORNER_MARGINS;
}

// Кнопка отмены в экране входящего вызова
#CallUi_RejectButton {
    background-image : meegotouch-callui-button-reject-background $CORNER_MARGINS;

    preferred-size   : 210px 128px;
    minimum-size     : 210px 128px;
    maximum-size     : 210px 128px;

    margin-left      : 12px; // 24px / 2
    margin-right     : 0;
    margin-top       : 0;
    margin-bottom    : 0;

    padding-left     : 0;
    padding-right    : 0;
    padding-top      : 0;
    padding-bottom   : 0;

    icon-align       : center;
    icon-size        : 48px 48px;

    press-feedback   : priority2_callbutton_press;
    release-feedback : priority2_callbutton_release;
    cancel-feedback  :;
}

#CallUi_RejectButton:pressed {
    background-image : meegotouch-callui-button-reject-background-pressed $CORNER_MARGINS;
}


// Кнопка "Снять трубку" в экране входящего вызова
#CallUi_AnswerButton {
    background-image : meegotouch-callui-button-answer-background $CORNER_MARGINS;

    preferred-size   : 210px 128px;
    minimum-size     : 210px 128px;
    maximum-size     : 210px 128px;

    margin-left      : 0;
    margin-right     : 12px; // 24px / 2
    margin-top       : 0;
    margin-bottom    : 0;

    padding-left     : 0;
    padding-right    : 0;
    padding-top      : 0;
    padding-bottom   : 0;

    icon-align       : center;
    icon-size        : 48px 48px;

    press-feedback   : priority2_callbutton_press;
    release-feedback : priority2_callbutton_release;
    cancel-feedback  :;
}

#CallUi_AnswerButton:pressed {
    background-image : meegotouch-callui-button-answer-background-pressed $CORNER_MARGINS;
}


#CallUi_SendMessageButton {
    background-image : meegotouch-callui-button-general-background $CORNER_MARGINS;

    preferred-size   : 210px 64px;
    minimum-size     : 210px 64px;
    maximum-size     : 210px 64px;

    margin-left      : 12px; // 18px -buttom group left margin
    margin-right     : 12px; // 24px / 2
    margin-top       : 0;
    margin-bottom    : 0;

    padding-left     : 0;
    padding-right    : 0;
    padding-top      : 0;
    padding-bottom   : 0;

    icon-align       : center;
    icon-size        : 48px 48px;

    press-feedback   :;
    release-feedback :;
    cancel-feedback  :;
}

#CallUi_SendMessageButton:pressed {
    background-image : meegotouch-callui-button-general-background-pressed $CORNER_MARGINS;
    background-color :;
}


#CallUi_IconButton {
    font                  : $FONT_FAMILY light 1.8mm;//18px
    text-color            : #8C8C8C;
    vertical-text-align   : vcenter;
    horizontal-text-align : hcenter;

    icon-size             : 64px 64px;
    icon-align            : center;

    background-color      :;
    background-image      :;

    margin-left           : 0px;
    margin-right          : 0px;
    margin-top            : 26px; // button margin (22) + separator bottom margin (4)
    margin-bottom         : 0px;

    minimum-size          : 95px 87px;  // full height (113) - top margin (26)
    preferred-size        : 95px 87px;
    maximum-size          : 95px 87px;

    press-feedback        :;
    release-feedback      :;
    cancel-feedback       :;

    text-margin-left      : 0;
    text-margin-top       : 5px;
    text-margin-right     : 0;
    text-margin-bottom    : 0;

    text-wrap-mode        : nowrap;
    text-eliding          : false;
}

#CallUi_IconButton:pressed {
    background-image :;
    background-color :;
}

#CallUi_IconButton:selected {
    background-image :;
    background-color :;
}


#CallUi_VideoButton {
    background-image : meegotouch-callui-button-shadowed-background $CORNER_MARGINS;
    background-color : none;


    preferred-size   : 210px 64px;
    minimum-size     : 210px 64px;
    maximum-size     : 210px 64px;

    icon-align       : center;
    icon-size        : 48px 48px;

    icon-id          : "icon-m-telephony-video-call-button";

    press-feedback   :;
    release-feedback :;
    cancel-feedback  :;

    margin-left      : 0;
    margin-right     : 0;
    margin-top       : 0;
    margin-bottom    : 24px;

    padding-left     : 0;
    padding-right    : 0;
    padding-top      : 0;
    padding-bottom   : 0;

    content-opacity  : 1.0;
}

#CallUi_VideoButton:pressed {
    background-image : meegotouch-callui-button-shadowed-background-pressed $CORNER_MARGINS;
    background-color : none;
}

#CallUi_VideoButton:disabled {
    background-image : meegotouch-callui-button-shadowed-background $CORNER_MARGINS;
    background-color : none;
    content-opacity  : 0.3;
}


#CallUi_SpeakerButton {
    font                  : $FONT_FAMILY light 1.8mm;//18px
    text-color            : #8C8C8C;
    vertical-text-align   : vcenter;
    horizontal-text-align : hcenter;

    icon-size             : 64px 64px;
    icon-align            : center;

    background-color      :;
    background-image      :;

    margin-left           : 0px;
    margin-right          : 14px;
    margin-top            : 26px; // button margin (22) + separator bottom margin (4)
    margin-bottom         : 0px;

    minimum-size          : 95px 92px;  // full height (113) - top margin (26) + text margin (5)
    preferred-size        : 95px 92px;
    maximum-size          : 95px 92px;

    press-feedback        :;
    release-feedback      :;
    cancel-feedback       :;

    text-margin-left      : 0;
    text-margin-top       : 0;
    text-margin-right     : 0;
    text-margin-bottom    : 0;

    text-wrap-mode        : nowrap;
    text-eliding          : false;
}

#CallUi_SpeakerButton:pressed {
    background-image :;
    background-color :;
}

#CallUi_SpeakerButton:selected {
    background-image :;
    background-color :;
}


#CallUi_MuteButton {
    font                  : $FONT_FAMILY light 1.8mm;//18px
    text-color            : #8C8C8C;
    vertical-text-align   : vcenter;
    horizontal-text-align : hcenter;

    icon-size             : 64px 64px;
    icon-align            : center;

    background-color      :;
    background-image      :;

    margin-left           : 15px;
    margin-right          : 15px;
    margin-top            : 26px; // button margin (22) + separator bottom margin (4)
    margin-bottom         : 0px;

    minimum-size          : 95px 92px;  // full height (113) - top margin (26) + text margin (5)
    preferred-size        : 95px 92px;
    maximum-size          : 95px 92px;

    press-feedback        :;
    release-feedback      :;
    cancel-feedback       :;

    text-margin-left      : 0;
    text-margin-top       : 0;
    text-margin-right     : 0;
    text-margin-bottom    : 0;

    text-wrap-mode        : nowrap;
    text-eliding          : false;
}

#CallUi_MuteButton:pressed {
    background-image :;
    background-color :;
}

#CallUi_MuteButton:selected {
    background-image :;
    background-color :;
}

#CallUi_MuteButton_Video {
    font                  : $FONT_FAMILY light 1.8mm;//18px
    text-color            : #C8C8C8;
    vertical-text-align   : vcenter;
    horizontal-text-align : hcenter;

    icon-size             : 64px 64px;
    icon-align            : center;

    background-color      :;
    background-image      :;

    margin-left           : 0;
    margin-right          : 0;
    margin-top            : $MARGIN_XLARGE;
    margin-bottom         : 0;

    padding-left          : 0;
    padding-right         : 0;
    padding-top           : 0;
    padding-bottom        : 0;

    minimum-size          : -1 87px;
    preferred-size        : -1 87px;
    maximum-size          : -1 87px;

    press-feedback        :;
    release-feedback      :;
    cancel-feedback       :;

    text-margin-left      : 0;
    text-margin-top       : 0;
    text-margin-right     : 0;
    text-margin-bottom    : 0;

    text-wrap-mode        : nowrap;
    text-eliding          : false;
}

#CallUi_MuteButton_Video:pressed {
    background-image :;
    background-color :;
}

#CallUi_MuteButton_Video:selected {
    background-image :;
    background-color :;
}


#CallUi_HoldButton {
    font                  : $FONT_FAMILY light 1.8mm;//18px
    text-color            : #8C8C8C;
    vertical-text-align   : vcenter;
    horizontal-text-align : hcenter;

    icon-size             : 64px 64px;
    icon-align            : center;

    background-color      :;
    background-image      :;

    margin-left           : 15px;
    margin-right          : 15px;
    margin-top            : 26px; // button margin (22) + separator bottom margin (4)
    margin-bottom         : 0px;

    minimum-size          : 95px 92px;  // full height (113) - top margin (26) + text margin (5)
    preferred-size        : 95px 92px;
    maximum-size          : 95px 92px;

    press-feedback        :;
    release-feedback      :;
    cancel-feedback       :;

    text-margin-left      : 0;
    text-margin-top       : 0;
    text-margin-right     : 0;
    text-margin-bottom    : 0;

    text-wrap-mode        : nowrap;
    text-eliding          : false;
}

#CallUi_HoldButton:pressed {
    background-image :;
    background-color :;
}

#CallUi_HoldButton:selected {
    background-image :;
    background-color :;
}


#CallUi_DialpadButton {
    font                  : $FONT_FAMILY light 1.8mm;//18px
    text-color            : #8C8C8C;
    vertical-text-align   : vcenter;
    horizontal-text-align : hcenter;

    icon-size             : 64px 64px;
    icon-align            : center;

    background-color      :;
    background-image      :;

    margin-left           : 14px;
    margin-right          : 0px;
    margin-top            : 26px; // button margin (22) + separator bottom margin (4)
    margin-bottom         : 0px;

    minimum-size          : 95px 92px;  // full height (113) - top margin (26) + text margin (5)
    preferred-size        : 95px 92px;
    maximum-size          : 95px 92px;

    press-feedback        :;
    release-feedback      :;
    cancel-feedback       :;

    text-margin-left      : 0;
    text-margin-top       : 0;
    text-margin-right     : 0;
    text-margin-bottom    : 0;

    text-wrap-mode        : nowrap;
    text-eliding          : false;
}

#CallUi_DialpadButton:pressed {
    background-image :;
    background-color :;
}

#CallUi_DialpadButton:selected {
    background-image :;
    background-color :;
}


#CallUi_ViewMenuButton {
    background-image :;
    background-color :;

    icon-align       : center;
    icon-size        : 48px 48px;

    preferred-size   : 48px 48px;
    minimum-size     : 48px 48px;
    maximum-size     : 48px 48px;

    press-feedback   :;
    release-feedback :;
    cancel-feedback  :;

    margin-left      :  0px;
    margin-right     :  0px;
    margin-top       : 16px;
    margin-bottom    :  0px;
}

#CallUi_ViewMenuButton:pressed {
    background-image :;
    background-color :;
}


#CallUi_SilenceButton {
    preferred-size   : 210px 64px;
    minimum-size     : 210px 64px;
    maximum-size     : 210px 64px;

    margin-left      : 0;
    margin-right     : 0;
    margin-top       : 0;
    margin-bottom    : 0;

    padding-left     : 0;
    padding-right    : 0;
    padding-top      : 0;
    padding-bottom   : 0;

    icon-align       : center;
    icon-size        : 48px 48px;

    press-feedback   :;
    release-feedback :;
    cancel-feedback  :;

    background-image : meegotouch-callui-button-shadowed-background $CORNER_MARGINS;
    background-color :;

    content-opacity  : 1.0;
}

#CallUi_SilenceButton:pressed {
    background-image : meegotouch-callui-button-shadowed-background-pressed $CORNER_MARGINS;
    background-color :;
}

#CallUi_SilenceButton:disabled {
    background-image : meegotouch-callui-button-shadowed-background $CORNER_MARGINS;
    background-color :;
    content-opacity  : 0.3;
}


#CallUi_ButtonGroup {
    margin-left    : 0;
    margin-right   : 0;
    margin-top     : 0;
    margin-bottom  : 0;

    padding-left   :  6px;
    padding-right  :  6px;
    padding-top    :  0px;
    padding-bottom : 24px;

    preferred-size : $PAGE_WIDTH 420px;
    minimum-size   : $PAGE_WIDTH 420px;
    maximum-size   : $PAGE_WIDTH 420px;
}

#CallUi_ButtonGroup_Incoming {
    margin-left    : 0;
    margin-right   : 0;
    margin-top     : 0;
    margin-bottom  : 0;

    padding-left   :  18px;
    padding-right  :  18px;
    padding-top    :  16px;
    padding-bottom : 113px;

    preferred-size : $PAGE_WIDTH 420px;
    minimum-size   : $PAGE_WIDTH 420px;
    maximum-size   : $PAGE_WIDTH 420px;
}

#CallUi_ButtonGroup_VideoPage_Incoming {
    margin-left    : 0;
    margin-right   : 0;
    margin-top     : 0;
    margin-bottom  : 0;

    padding-left   :  16px;
    padding-right  :  16px;
    padding-top    :  16px;
    padding-bottom :  24px;

    preferred-size : $PAGE_WIDTH 240px;
    minimum-size   : $PAGE_WIDTH 240px;
    maximum-size   : $PAGE_WIDTH 240px;
}

#CallUi_SplitButton {
    icon-size             : 64px 64px;
    icon-align            : center;

    background-image      :;
    background-color      :;

    margin-left           : 16px;
    margin-right          : 0;
    margin-top            : 0;
    margin-bottom         : 0;

    minimum-size          : 64px 64px;
    preferred-size        : 64px 64px;
    maximum-size          : 64px 64px;

    press-feedback        :;
    release-feedback      :;
    cancel-feedback       :;
}

#CallUi_SplitButton:pressed {
    background-image :;
    background-color :;
}


#CallUi_DropButton {
    icon-size             : 64px 64px;
    icon-align            : center;

    background-image      :;
    background-color      :;

    margin-left           : 16px;
    margin-right          : 0;
    margin-top            : 0;
    margin-bottom         : 0;

    minimum-size          : 64px 64px;
    preferred-size        : 64px 64px;
    maximum-size          : 64px 64px;

    press-feedback        : priority2_callbutton_press;
    release-feedback      : priority2_callbutton_release;
    cancel-feedback       :;
}

#CallUi_DropButton:pressed {
    background-image :;
    background-color :;
}


// The mode switch slider
SliderWidgetStyle {
    minimum-size     : 128px 64px;
    preferred-size   : 128px 64px;
    maximum-size     : 128px 64px;

    margin-bottom    : 0;
    margin-right     : $MARGIN_XLARGE;
    margin-top       : $MARGIN_XLARGE;
    margin-left      : 0;

    padding-left     : 0;
    padding-right    : 0;
    padding-top      : 0;
    padding-bottom   : 0;

    size             : 128px 64px;

    thumb-size       : 54px 54px;
    thumb-margin     : 5px;

    icon-size        : 48px 48px;
    icon-margin      : 8px;

    background-image : meegotouch-videocall-camera-switch-background $CORNER_MARGINS;
    background-color :;

    press-feedback   :;
    release-feedback :;
}


// ***************************************************************************
// ** generic layout/policy without margins or spacing ***********************

#ZeroLayout {
    vertical-spacing   : 0;
    horizontal-spacing : 0;

    margin-left        : 0;
    margin-right       : 0;
    margin-top         : 0;
    margin-bottom      : 0;
}


// ***************************************************************************
// ** invisible widget *******************************************************

#ZeroSizeWidget {
    minimum-size   : 0 0;
    maximum-size   : 0 0;
    preferred-size : 0 0;

    margin-left    : 0;
    margin-right   : 0;
    margin-top     : 0;
    margin-bottom  : 0;

    padding-left   : 0;
    padding-right  : 0;
    padding-top    : 0;
    padding-bottom : 0;

    background-image : none;
}


// ***************************************************************************
// ** icons ******************************************************************

#CallUi_InfoIcon_Single {
    margin-left    : $MARGIN_XLARGE;
    margin-right   : 0;
    margin-top     : 0;
    margin-bottom  : 0;

    padding-left   : 0;
    padding-right  : 0;
    padding-top    : 0;
    padding-bottom : 0;

    minimum-size   : 32px 32px;
    maximum-size   : 32px 32px;
    preferred-size : 32px 32px;
}

#CallUi_InfoIcon_Left {
    margin-left    : $MARGIN_XLARGE;
    margin-right   : 0;
    margin-top     : 0;
    margin-bottom  : 0;

    minimum-size   : 32px 32px;
    maximum-size   : 32px 32px;
    preferred-size : 32px 32px;
}

#CallUi_InfoIcon_Right {
    margin-left    : $MARGIN_LARGE;
    margin-right   : 0;
    margin-top     : 0;
    margin-bottom  : 0;

    minimum-size   : 32px 32px;
    maximum-size   : 32px 32px;
    preferred-size : 32px 32px;
}

#CallUi_MinimizedCallIcon {
    maximum-size   : 32px 32px;
    minimum-size   : 32px 32px;
    preferred-size : 32px 32px;

    margin-left    : 0;
    margin-right   : 0;
    margin-top     : 0;
    margin-bottom  : 0;
}


// ***************************************************************************
// ** labels *****************************************************************

#CallUi_BalanceLabel {
    margin-left   : $MARGIN_XLARGE;
    margin-right  : 0;
    margin-top    : 0;
    margin-bottom : 0;

    minimum-size  : 0 0;

    font          : $FONT_FAMILY light 1.8mm ;//18px
    color         : #C8C8C8;
}

#CallUi_DurationLabel {
    margin-left   : $MARGIN_XLARGE;
    margin-right  : 0;
    margin-top    : 0;
    margin-bottom : 0;

    minimum-size  : 0 0;

    font          : $FONT_FAMILY light 2.2mm ;//22px
    color         : #C8C8C8;
}

#CallUi_DurationLabel_Minimised {
    margin-left   : $MARGIN_XLARGE;
    margin-right  : 0;
    margin-top    : 0;
    margin-bottom : 0;

    minimum-size  : 0 0;

    font          : $FONT_FAMILY light 2.2mm ;//22px
    color         : #C8C8C8;
}

#CallUi_NameLabel_In_Out {
    margin-left   : $MARGIN_XLARGE;
    margin-right  : 0;
    margin-top    : 0;
    margin-bottom : 0;

    minimum-size  : 0 0;
    maximum-size  : -1 38px;

    font          : $FONT_FAMILY bold 3.2mm ;//32px
    color         : #FFFFFF;
}

#CallUi_NameLabel_Ongoing {
    margin-left   : $MARGIN_XLARGE;
    margin-right  : 0;
    margin-top    : 0;
    margin-bottom : 0;

    minimum-size  : 0 0;
    maximum-size  : -1 38px;

    font          : $FONT_FAMILY bold 3.2mm ;//32px
    color         : #62B700;
}

#CallUi_NameLabel_Held {
    margin-left   : $MARGIN_XLARGE;
    margin-right  : 0;
    margin-top    : 0;
    margin-bottom : 0;

    minimum-size  : 0 0;
    maximum-size  : -1 38px;

    font          : $FONT_FAMILY bold 3.2mm ;//32px
    color         : #C8C8C8;
}

#CallUi_NameLabel_Ended {
    margin-left   : $MARGIN_XLARGE;
    margin-right  : 0;
    margin-top    : 0;
    margin-bottom : 0;

    minimum-size  : 0 0;
    maximum-size  : -1 38px;

    font          : $FONT_FAMILY bold 3.2mm ;//32px
    color         : #FF4036;
}

#CallUi_NameLabel_Minimised_In_Out {
    margin-left   : $MARGIN_XLARGE;
    margin-right  : 0;
    margin-top    : 0;
    margin-bottom : 0;

    minimum-size  : 0 0;

    font          : $FONT_FAMILY bold 2.4mm ;//24px
    color         : #FFFFFF;
}

#CallUi_NameLabel_Minimised_Ongoing {
    margin-left   : $MARGIN_XLARGE;
    margin-right  : 0;
    margin-top    : 0;
    margin-bottom : 0;

    minimum-size  : 0 0;

    font          : $FONT_FAMILY bold 2.4mm ;//24px
    color         : #62B700;
}

#CallUi_NameLabel_Minimised_Held {
    margin-left   : $MARGIN_XLARGE;
    margin-right  : 0;
    margin-top    : 0;
    margin-bottom : 0;

    minimum-size  : 0 0;

    font          : $FONT_FAMILY bold 2.4mm ;//24px
    color         : #C8C8C8;
}

#CallUi_NameLabel_Minimised_Ended{
    margin-left   : $MARGIN_XLARGE;
    margin-right  : 0;
    margin-top    : 0;
    margin-bottom : 0;

    minimum-size  : 0 0;

    font          : $FONT_FAMILY bold 2.4mm ;//24px
    color         : #FF4036;
}

#CallUi_StatusLabel {
    margin-left   : $MARGIN_XLARGE;
    margin-right  : 0;
    margin-top    : 0;
    margin-bottom : 0;

    minimum-size  : 0 0;

    font          : $FONT_FAMILY light 1.8mm ;//18px
    color         : #C8C8C8;
}

#CallUi_StatusLabel_Minimised {
    margin-left   : $MARGIN_XLARGE;
    margin-right  : 0;
    margin-top    : 0;
    margin-bottom : 0;

    minimum-size  : 0 0;

    font          : $FONT_FAMILY light 1.8mm ;//18px
    color         : #C8C8C8;
}

#CallUi_IncomingInfoLabel {
    margin-left   : $MARGIN_XLARGE;
    margin-right  : 0;
    margin-top    : 0;
    margin-bottom : 0;

    minimum-size  : 0 0;

    font          : $FONT_FAMILY light 2.2mm ;//22px
    color         : #FF4036; // warning color
}

#CallUi_CameraModeLabel {
    margin-left    : 0;
    margin-right   : 0;
    margin-top     : 0;
    margin-bottom  : 0;

    minimum-size   : 128px 23px;
    preferred-size : 128px 23px;
    maximum-size   : 128px 23px;

    font           : $FONT_FAMILY light 1.8mm ;//18px
    color          : #C8C8C8;
}

// ***************************************************************************
// ** Call UI - custom style for all the random stuff ************************
CustomAttributesStyle {

    // CallWidget y-position in different configurations
    call-pos-1     : 274; // From ALG: 64 +64 +63 +72 +12 (-1px correction for ALG values)
    call-pos-2-2   :   0; // always on top of the screen
    call-pos-3     :   0; // always on top of the screen
    call-pos-2-3   :  64; // below $CALLWIDGET_SIZE_MINIMIZED.height (64px)
}


// ***************************************************************************
// ** CallWidget *************************************************************

CallWidgetStyle {
    margin-left            : 0;
    margin-right           : 0;
    margin-top             : 0;
    margin-bottom          : 0;

    padding-left           : 0;
    padding-right          : 0;
    padding-top            : 0;
    padding-bottom         : 0;

    reactive-margin-left   : 0;
    reactive-margin-right  : 0;
    reactive-margin-top    : 0;
    reactive-margin-bottom : 0;

    press-feedback         :;
    release-feedback       :;
    cancel-feedback        :;

    background-image       :;
    background-color       :;

    minimum-size           : $CALLWIDGET_SIZE;
    maximum-size           : $CALLWIDGET_SIZE;
    preferred-size         : $CALLWIDGET_SIZE;

    // end button needs separate margins to prevent reactive area outside button graphics
    end-button-margin-left    : 129px; // spec margin (135px) -button group padding (6px)
    end-button-margin-right   : 50px; // spec margin

    view-menu-button-margin-right : 31px; // original margin (37px) - button group padding (6px)

    // some video view specific values
    video-controls-bg-pos     : 592px 0px ; // FULL LS PAGE WIDTH (854px) -PREVIEW VIDEO WIDTH (246px) -PREVIEW VIDEO MARGINS (16px)
    video-controls-bg-size    : 262px 444px; // PREVIEW VIDEO WIDTH (246px) -PREVIEW VIDEO MARGINS (16px), FULL PAGE HEIGHT - STATUS BAR
    video-controls-bg-size-fs : 262px 444px; // PREVIEW VIDEO WIDTH (246px) -PREVIEW VIDEO MARGINS (16px), FULL PAGE HEIGHT - STATUS BAR
    // TODO: use this once we are able to hide the the status bar
    //video-controls-bg-size-fs : 262px 480px; // PREVIEW VIDEO WIDTH (246px) -PREVIEW VIDEO MARGINS (16px), FULL PAGE HEIGHT

    video-controls-bg-opacity : 0.30;
}

#CallWidget_Minimized {
    minimum-size     : $CALLWIDGET_SIZE_MINIMIZED;
    maximum-size     : $CALLWIDGET_SIZE_MINIMIZED;
    preferred-size   : $CALLWIDGET_SIZE_MINIMIZED;

    background-image : meegotouch-callui-second-waiting-call-background;
}

#CallWidget_Video_Maximized {
    minimum-size     : $CALLWIDGET_SIZE_VIDEO_MAXIMIZED;
    maximum-size     : $CALLWIDGET_SIZE_VIDEO_MAXIMIZED;
    preferred-size   : $CALLWIDGET_SIZE_VIDEO_MAXIMIZED;

    margin-left      : 187px;
}

#CallWidget_Video_Minimized {
    minimum-size     : $CALLWIDGET_SIZE_VIDEO_MINIMIZED;
    maximum-size     : $CALLWIDGET_SIZE_VIDEO_MINIMIZED;
    preferred-size   : $CALLWIDGET_SIZE_VIDEO_MINIMIZED;

    background-image : meegotouch-callui-second-waiting-call-background;
}

#CallWidget_Video {
    minimum-size     : $CALLWIDGET_SIZE_VIDEO;
    maximum-size     : $CALLWIDGET_SIZE_VIDEO;
    preferred-size   : $CALLWIDGET_SIZE_VIDEO;

    background-color : #000000;
}


// ***************************************************************************
// ** call bubble widget *****************************************************

CallBubbleStyle {
    margin-left            : $MARGIN_XLARGE;
    margin-right           : $MARGIN_XLARGE;
    margin-top             : 0;
    margin-bottom          : 0;

    padding-left           : 0;
    padding-right          : 0;
    padding-top            : 10px; // FIXME!
    padding-bottom         : 18px; // FIXME!

    reactive-margin-left   : 0;
    reactive-margin-right  : 0;
    reactive-margin-top    : 0;
    reactive-margin-bottom : 0;

    press-feedback         :;
    release-feedback       :;
    cancel-feedback        :;

    minimum-size           : 448px 72px; // $PAGE_WIDTH (480px) - 2 * $MARGIN_XLARGE (2*16px)
    maximum-size           : 448px 72px; // $PAGE_WIDTH (480px) - 2 * $MARGIN_XLARGE (2*16px)
    preferred-size         : 448px 72px; // $PAGE_WIDTH (480px) - 2 * $MARGIN_XLARGE (2*16px)

    background-image       : meegotouch-callui-bubble-background $CORNER_MARGINS;
    background-color       :;


    // ** CallBubble specific items **

    bubble-pos: 0px 190px; // 64 +64 +63 (-1px correction for ALG values)

    // animation update interval (fps)
    animation-fps: 15;

    // appear animation duration
    appear-time: 750; // ms

    // disappear animation duration
    disappear-time: 250; //ms

    // bubble hide delay
    hide-delay: 5000; // ms

    // service icon size (see #CallBubbleIcon)
    icon-size: 32px 32px;
}

#CallBubbleText {
    margin-left   : 14px;
    margin-right  : 14px;
    margin-top    : 0;
    margin-bottom : 0;

    font          : $FONT_FAMILY light uppercase 1.6mm;
    color         : #FFFFFF;
}

#CallBubbleIcon {
    margin-left    : 0;
    margin-right   : 14px;
    margin-top     : 0;
    margin-bottom  : 0;

    padding-left   : 0;
    padding-right  : 0;
    padding-top    : 0;
    padding-bottom : 0;

    minimum-size   : 32px 32px;
    maximum-size   : 32px 32px;
    preferred-size : 32px 32px;
}

#CommonItemDividerInverted {
    margin-top     : $MARGIN_LARGE;
}

// ** Speaker Dialog ********************************************************

#SpeakerDialogButton {
    font           : $FONT_FAMILY light 2.0mm ; //20px
    text-color     : #ffffff;

    vertical-text-align   : vcenter;
    horizontal-text-align : hcenter;

    icon-size             : 64px 64px;
    icon-align            : center;

    background-color      :;
    background-image      :;

    margin-left           : 16px;
    margin-right          : 16px;
    margin-top            : 47px;
    margin-bottom         : 35px;

    minimum-size          : -1 112px;
    preferred-size        : -1 112px;
    maximum-size          : -1 112px;

    press-feedback        :;
    release-feedback      :;
    cancel-feedback       :;
}

#SpeakerDialogButton:selected {
    font           : $FONT_FAMILY light 2.0mm ; //20px
    text-color     : #0F9900;

    vertical-text-align   : vcenter;
    horizontal-text-align : hcenter;

    icon-size             : 64px 64px;
    icon-align            : center;

    background-color      :;
    background-image      :;

    margin-left           : 16px;
    margin-right          : 16px;
    margin-top            : 47px;
    margin-bottom         : 35px;

    minimum-size          : -1 112px;
    preferred-size        : -1 112px;
    maximum-size          : -1 112px;

    press-feedback        :;
    release-feedback      :;
    cancel-feedback       :;
}

// ** Service Provider Dialog ***********************************************
#CallUiServiceProviderCharacterCounter
{
    margin-left : 24px;
    margin-right: 24px;
}


// ** screen lock widget *****************************************************

ScreenLockEventStyle {
    title-font         : $FONT_FAMILY bold 4.8mm ;//48px
    title-color        : $COLOR_INVERTED_FOREGROUND;

    sub-title-font     : $FONT_FAMILY light 2.6mm ;//26px
    sub-title-color    : $COLOR_INVERTED_FOREGROUND;

    text-area-color    : "#64AF2D";

    forward-icon       : icon-m-telephony-call-diverted 32 32;
    service-icon-size  : 32 32;

    minimum-size       : $PAGE_WIDTH 130;
    preferred-size     : $PAGE_WIDTH 130;
    maximum-size       : $PAGE_WIDTH 190;

    background-color   : #000000;
    background-opacity : 0.8;

    // left margin 16px
    right-margin       : 16;

    title-line-1-pos   : 16   60;
    title-line-2-pos   : 16  120;

    sub-title-pos      : 16  168;

    icon-pos-1        : 432 136; // left_pos = page_width(480) -right_margin(16) -icon_size(32)
    icon-pos-2        : 395 136; // left_pos = service_icon_pos -icon_spacer(5) -icon_size(32)
}

// * Participant Dialog *******************************************************

#CallUiParticipantIconButton {
    minimum-size   : $SIZE_BUTTON $SIZE_BUTTON;
    preferred-size : $SIZE_BUTTON $SIZE_BUTTON;
    maximum-size   : $SIZE_BUTTON $SIZE_BUTTON;

    margin-left    : $MARGIN_DEFAULT;
    margin-top     : $MARGIN_LARGE;
    margin-right   : $INDENT_DEFAULT;
    margin-bottom  : $MARGIN_LARGE;

    icon-size      : $SIZE_ICON_XLARGE $SIZE_ICON_XLARGE;
}


// ** End of File ************************************************************
Скачать: оригинальная call-ui_pr1.3.css, модифицированная call-ui_pr1.3_mod.css

Инсталляция:

  1. Подключите телефон по USB в режиме "mass storage" и скопируйте call-ui_pr1.3_mod.css в каталог Downloads.
  2. Отключите телефон от USB.
  3. Запустите терминал и введите следующие команды:
    devel-su
    Password: rootme
    cd /home/user/MyDocs/Downloads
    cp call-ui_pr1.3_mod.css /usr/share/themes/base/meegotouch/call-ui/style/call-ui.css
    /sbin/reboot
    

Деинсталляция:

  1. Подключите телефон по USB в режиме "mass storage" и скопируйте call-ui_pr1.3.css в каталог Downloads.
  2. Отключите телефон от USB.
  3. Запустите терминал и введите следующие команды:
    devel-su
    Password: rootme
    cd /home/user/MyDocs/Downloads
    cp call-ui_pr1.3.css /usr/share/themes/base/meegotouch/call-ui/style/call-ui.css
    /sbin/reboot
    



Update 2012/03/07


В процессе тестирования обнаружились недочеты, которые сейчас устраняются.
Поэтому с установкой этого мода советую пока подождать.
Обсуждение на форуме http://forum.allnokia.ru/. Пожелания лучше постить сюда, что бы мне их было легче отслеживать. Если лень писать сюда, то постите в ветку форума.
После исправления ошибок и доработки соберу deb-пакет, чтобы не гемороиться с терминалом.


Update 2012/03/12


Увеличил кнопки в двух экранах. Обновленную версию опубликовал.



Update 2012/07/04


В связи с обновлением PR1.3 произвел ревизию и обновил мод и инструкцию.

четверг, 16 февраля 2012 г.

Банальные флаги раскладки Ubuntu

Я уже запарился каждый раз рисовать или отыскивать флаги раскладки клавиатуры для Ubuntu.
Чтобы больше не париться решил положить их здесь в блоге. Может кому пригодятся тоже.
Скачать: тыц.

Поставить можно так: $ mkdir -p ~/.icons/flags $ cd ~/.icons/flags $ wget https://od.lk/d/58719109_khKg0/flags.tar.gz $ tar xzvf flags.tar.gz $ gsettings set org.gnome.libgnomekbd.indicator show-flags true Затем нужно перелогиниться или перезагрузиться.

Для выбора соответствующего набора флагов можно запустить скрипт, из архива: $ cd ~/.icons/flags $ ./sf 01 где 01 - номер набора от 01 до 15.


07/05/2012 - добавил в архив индикаторы раскладки для Gnome 3
01/07/2012 - обновил архив до 15 иконок

пятница, 3 февраля 2012 г.

Ссылки Nokia N9

Документация

Форумы


Сайты, Порталы

Блоги

Приложения

Создание иконок on-line

Неофициальные репозитории, моды

суббота, 28 января 2012 г.

Прошивка Nokia N9 в Ubuntu 11.10

В процессе проведения экспериментов над моей Nokia N9 я превратил ее в черненький кирпичик, весело подмигивающий мне светодиодом.
Это значит, что пора осваивать перепрошивку.

Для прошивки Firmware под Ubuntu необходима утилита flasher.
Скачать ее можно отсюда: http://tablets-dev.nokia.com/maemo-dev-env-downloads.php
Для 64-битной версии я использовал flasher_3.12.1_amd64.deb
Firmware Nokia N9 64 GB: DFL61_HARMATTAN_20.2011.40-4_PR_LEGACY_001-OEM158_ARM.zip скачать и распаковать.


Перепрошивка выполняется так: $ sudo flasher -F DFL61_HARMATTAN_22011.40-4_PR_LEGACY_001-OEM1-958_ARM.bin -f flasher 3.12.1 (Oct 5 2011) Harmattan WARNING: This tool is intended for professional use only. Using it may result in permanently damaging your device or losing the warranty. Suitable USB interface (bootloader/phonet) not found, waiting... USB device found at bus 003, device address 033. Device identifier: 387330412376462 (SN: N/A) Found device RM-696, hardware revision 1501 NOLO version 2.1.5 Version of 'sw-release': DFL61_HARMATTAN_20.2011.40-4_PR_001 Sending ape-algo image (7032 kB)... 100% (7032 of 7032 kB, avg. 12104 kB/s) Suitable USB interface (phonet) not found, waiting... USB device found at bus 003, device address 034. Device identifier: 387330412376462 (SN: N/A) Raw data transfer EP found at EP2. Ping attempt 1 (250 ms) Server application: 1.6.3 Found product RM-696 rev. 1501 Server implements softupd protocol version 1.8 Image SW version DFL61_HARMATTAN_20.2011.40-4_PR_001 Image moslo not present Image mmc not present Image tar skipped Image config skipped Battery level 19 %, continuing. image [state progress transfer flash speed] --------------------------------------------------------------------- [x] cert-sw [finished 100 % 1 / 1 kB NA ] [x] cmt-2nd [finished 100 % 95 / 95 kB NA ] [x] cmt-algo [finished 100 % 789 / 789 kB NA ] [x] cmt-mcusw [finished 100 % 6050 / 6050 kB 2908 kB/s] [x] xloader [finished 100 % 23 / 23 kB NA ] [x] secondary [finished 100 % 93 / 93 kB NA ] [x] kernel [finished 100 % 2712 / 2712 kB 1859 kB/s] [x] rootfs [finished 100 % 1102340 / 1102340 kB 12547 kB/s] Updating SW release Success $ Область программ будет девственно чистой, как у нового аппарата. Контакты и почта останутся.


Полезные ссылки:

среда, 25 января 2012 г.

Не монтируется CD-RW в Ubuntu

У меня бывали случаи, что некоторые CD-RW диски переставали монтироваться. Происходило это либо после ошибки записи, либо еще по какой причине. Я обычно не разбирался долго, а просто выбрасывал такую болванку и брал новую.

На самом деле CD-RW, который не монтируется можно попытаться восстановить. Для этого нужно восстановить на нем файловую структуру.

В два приема:
  1. Определим куда подключено устройство: $ cdrecord -scanbus scsibus6: 6,0,0 600) 'TSSTcorp' 'CDDVDW SN-S082N ' 'LA00' Removable CD-ROM 6,1,0 601) * 6,2,0 602) * 6,3,0 603) * 6,4,0 604) * 6,5,0 605) * 6,6,0 606) * 6,7,0 607) *
  2. Затем даем команду стирания CD-RW. В качестве параметра dev подставляем адрес 6,0,0 , который определился выше. $ sudo cdrecord blank=all -force dev=6,0,0 И примерно через 8-16 минут (В зависимости от максимальной скорости привода) получаем сообщение от системы, что диск смонтирован
Теперь можно на него записывать иcкоробочной программой Brothero.


Полезные ссылки:

понедельник, 9 января 2012 г.

Настройка энергопотребления ThinkPad x220 в Ubuntu 12.04

Куратор темы на ixbt о ноутбуке ThinkPad x220 попросил написать меня статью об оптимизации потребления на ThinkPad x220, что я и сделал.
На мой взгляд статья получилась хорошей, но ixbt устроен так, что я не могу делать там обновления.
Поэтому я публикую ее в моем блоге. Здесь будут вноситься изменения, если таковые появятся.
А когда будет время поправлю структуру и ссылки в основной статье об экономии электричества в линуксе.

На все про все, если вы делаете это в первый раз, запаситесь примерно 2-мя часами.

Потребление замеряется в idle и с уровнем подсветки дисплея 20%. Когда систему "успокоилась" и переходные процессы завершены.

Каждый раздел оптимизации не зависит от другого и может быть применен отдельно.

  1. Установка и настройка pm-utils
    1. Установить необходимые программы: apmd, pm-utils и т.п. $ sudo apt-get install apmd pm-utils hdparm libnotify-bin
    2. Создадим скрип управления энергопотреблением: $ sudo gedit /usr/lib/pm-utils/power.d/99-savings.sh В появившемся окне редактора копипастим следующий текст
      ######################################################################################
      # A script to aggressively toggle power management between high 
      # performance and very low power consumption.
      # For more information on each of these options, see http://www.lesswatts.org
      # Last version script see http://axa-ru.blogspot.com/2012/01/thinkpad-x220-powersaving.html
      ################# Changes history ###################################################
      #VERSION=0.12   # 31.08.2010 Testing Ubuntu 10.04. Small changes for Wi-Fi control
      #VERSION=0.13   # 21.09.2010 Adding services control: 
                      #   evolution-alarm-notify, 
                      #   postfix, 
                      #   rsyslog
      #VERSION=0.2    # 23.07.2011 Modified for Ubintu 11.04 for Thinkpad x220 4290rw1
      #VERSION=0.23   # 27.07.2011 Added store value (Brightness, user, etc ) to /tmp/powersave.ini
                      #   Fix notify-send message
                      #   Added CPU core disabling. Disable cores not affected for power saving
      #VERSION=0.23.1 # 07.01.2012 Fix ethtool parameters in aLan procedure
                      #     
      #VERSION=0.23.2 # 07.01.2012 Fix aBrightness procedure
      VERSION=0.24    # 08.01.2012 Added start/stop conky monitor
      
      #
      # To install:
      #
      # sudo apt-get install apmd pm-utils expect hdparm libnotify-bin
      #
      # Save this file to /usr/lib/pm-utils/power.d/99-savings.sh
      # cd /usr/lib/pm-utils/power.d
      # sudo install 99-savings.sh /etc/pm/sleep.d
      # sudo install 99-savings.sh /etc/pm/power.d
      #
      
      INI_DIR=/tmp
      INI_FILE=powersave.ini
      INI=${INI_DIR}/${INI_FILE}
      
      aUsb()
      {
        #################################################
        ## USB Subsystem
        ##
        # 0.7-0.8 W
        case "$1" in
          false)  #ac_power
            for i in /sys/bus/usb/devices/*/power/control
            do
              echo "on" > $i
            done
            ;;
      
          true)  #batt_power
            for i in /sys/bus/usb/devices/*/power/control
            do
              echo "auto" > $i
            done
      
            for i in /sys/bus/usb/devices/*/power/autosuspend
            do
              echo 1 > $i
            done
      
            echo 1 > /sys/module/usbcore/parameters/autosuspend
            ;;
        esac
      }
      
      aSata()
      {
        case "$1" in
          false)  #ac_power
            # Set the SATA to max performance
            for i in /sys/class/scsi_host/host*/link_power_management_policy
            do
              echo max_performance > $i
            done
            ;;
      
          true)  #batt_power
            # Set SATA to minimum power
            # 0.7 W
            for i in /sys/class/scsi_host/host*/link_power_management_policy
            do
              echo min_power > $i
            done
            ;;
        esac
      }
      
      aPci()
      {
        case "$1" in
          false)  #ac_power
            for i in /sys/bus/pci/devices/*/power/control
            do
              echo on > $i
            done
            ;;
      
          true)  #batt_power
            for i in /sys/bus/pci/devices/*/power/control
            do
              echo auto > $i
            done
            ;;
        esac
      }
      
      aI2c()
      {
        case "$1" in
          false)  #ac_power
            for i in /sys/bus/i2c/devices/i2c-*/power/control
            do
              echo on > $i
            done
            ;;
      
          true)  #batt_power
            for i in /sys/bus/i2c/devices/i2c-*/power/control
            do
              echo auto > $i
            done
            ;;
        esac
      }
      
      aHdd()
      {
        case "$1" in
          false)  #ac_power
            # Set the drive to mostly stay awake.  Some may want to change -B 200
            # to -B 255 to avoid accumulating Load_Cycle_Counts
            # -S 240 => put in standby after 20 minutes idle
            # -B 200 => do not permit spindown
            # -M => not supported by my drive
            hdparm -B 200 -S 240 -M 254 /dev/sda
      
            # Remount ext3/4 filesystems so the journal commit only happens every 60
            # seconds.  By default this is 5 but, I prefer to reduce the disk
            # activity a bit.
            mount -o remount,commit=60,atime /
            ;;
      
          true)  #batt_power
            hdparm -B 1 -S 4 -M 128 /dev/sda
            mount -o remount,noatime,commit=600 /
      
            ;;
        esac
      }
      
      aSsd()
      {
      
      # add these commands in the /etc/rc.local
      #  echo deadline > /sys/block/sda/queue/scheduler
      #  echo 1 > /sys/block/sda/queue/iosched/fifo_batch
      #  sysctl -w vm.swappiness=1            # Strongly discourage swapping
      #  sysctl -w vm.vfs_cache_pressure=50   # Don't shrink the inode cache aggressively
        case "$1" in
          false)  #ac_power
            ;;
      
          true)  #batt_power
            ;;
        esac
      }
      
      aI915()
      {
        case "$1" in
          false)  #ac_power
            echo 0 > /sys/module/i915/parameters/powersave
            ;;
      
          true)  #batt_power
            echo 1 > /sys/module/i915/parameters/powersave
            ;;
        esac
      }
      
      aWlan()
      {
            # WiFi power savings.
        case "$1" in
          false)  #ac_power
            /sbin/iwconfig wlan0 power off txpower 14
            ;;
      
          true)  #batt_power
            /sbin/iwconfig wlan0 power on txpower 4
            ;;
        esac
      }
      
      aLan()
      {
        case "$1" in
          false)  #ac_power
            # set the ethernet max speed.
            ethtool -s eth0 speed 1000 duplex full autoneg on wol d
            ;;
          true)  #batt_power
            # set the ethernet power savings.
            # ~ 0.4 W
            ethtool -s eth0 speed 10 duplex half autoneg off wol d
            ;;
        esac
      }
      
      aCpu()
      {
        #################################################
        ## CPU
        ##
      
        case "$1" in
          false)  #ac_power
            for i in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
            do
              echo performance > $i
            done
      
            # Enable All Core CPU
            for i in /sys/devices/system/cpu/cpu*/online
            do
              echo 1 > $i
            done
      
            # Set max freq 2.7 GHz
      #      for i in /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq
      #      do
      #        echo 2701000 > $i
      #      done
      
            # Shedule Multitreading
            echo 0 > /sys/devices/system/cpu/sched_mc_power_savings
            ;;
      
          true)  #batt_power
            for i in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
            do
              echo powersave > $i
            done
      
            # Set max freq 1 GHz
      #      for i in /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq
      #      do
      #        echo 1000000 > $i
      #      done
      
      #      Disable cores not affected for power saving
      #      for i in /sys/devices/system/cpu/cpu*/online
      #      do
      #        echo 0 > $i
      #      done
      
            echo 1 > /sys/devices/system/cpu/sched_mc_power_savings
            ;;
        esac
      }
      
      aSnd()
      {
        case "$1" in
          false)  #ac_power
            echo 0 > /sys/module/snd_hda_intel/parameters/power_save
            ;;
      
          true)  #batt_power
            # Turn off sound card power savings
            # < 0.1 W
            echo 10 > /sys/module/snd_hda_intel/parameters/power_save
            ;;
        esac
      }
      
      aBt()
      {
        case "$1" in
          false)  #ac_power
            # Enable the bluetooth driver
            rfkill unblock bluetooth
            ;;
      
          true)  #batt_power
            # Remove the bluetooth driver
            # 0.3-0.4 W
            rfkill block bluetooth
            ;;
        esac
      }
      
      aDaemons()
      {
        #################################################
        ## demons, services
        ##
      
        case "$1" in
          false)  #ac_power
            # 1. Evolution alarm and integrations
            /usr/lib/evolution/2.32/evolution-alarm-notify &
            #/usr/lib/evolution/e-calendar-factory &
            #/usr/lib/evolution/e-addressbook-factory &
      
            # 2. Starting Sendmail server 
            #postfix start 
      
            # 3. Starting CouchDB & desktopcouch
            dbus-send --session --dest=org.desktopcouch.CouchDB --print-reply --type=method_call / org.desktopcouch.CouchDB.getPort
      
            # 4. Starting conky
            if [ ${CONKY_RUN} -eq 1 ]; then
              su $vUSER -c "/usr/bin/conky --display=:0 &"
            fi
            ;;
      
          true)  #batt_power
            # 1. Evolution alarm
            killall evolution-alarm-notify
            #killall e-calendar-factory
            #killall e-addressbook-factory
      
            # 2. Stopping Sendmail server 
            #postfix stop
      
            # 3. Stoping CouchDB & desktopcouch
            killall beam.smp
            killall desktopcouch-service
      
            # Stoping conky ~1W
            killall conky
            ;;
        esac
      }
      
      # < 0.1 W
      aWebcam()
      {
        case "$1" in
          false)  #ac_power
            # Enable the webcam driver
            modprobe uvcvideo
            ;;
      
          true)  #batt_power
            # Remove the webcam driver
            modprobe -r uvcvideo
            ;;
        esac
      }
      
      aMemory()
      {
        case "$1" in
          false)  #ac_power
            # Set kernel dirty page value back to default
            echo 10 > /proc/sys/vm/dirty_ratio
            echo 5 > /proc/sys/vm/dirty_background_ratio
      
            # Only wakeup every 60 seconds to see if we need to write dirty pages
            # By default this is every 5 seconds but, I prefer 60 to reduce disk
            # activity.
            echo 6000 > /proc/sys/vm/dirty_writeback_centisecs
            ;;
      
          true)  #batt_power
            # Reduce disk activity by waiting up to 10 minutes before doing writes
            echo 90 > /proc/sys/vm/dirty_ratio
            echo 1 > /proc/sys/vm/dirty_background_ratio
            echo 60000 > /proc/sys/vm/dirty_writeback_centisecs
            ;;
        esac
      }
      
      aBrightness()
      {
        case "$1" in
          false)  #ac_power
            # Setup maximum brigthness
            # Thinkpad x220, Ubuntu 11.04
            vBAT_BRI=$(cat /sys/class/backlight/acpi_video0/brightness)
            echo $vAC_BRI > /sys/class/backlight/acpi_video0/brightness
            ;;
      
          true)  #batt_power
            # Setup brigthness 30%
            vAC_BRI=$(cat /sys/class/backlight/acpi_video0/brightness)
            echo $vBAT_BRI > /sys/class/backlight/acpi_video0/brightness
            ;;
        esac
      }
      
      aMisk()
      {
        case "$1" in
          false)  #ac_power
            # Turn off the laptop mode disk optimization
            echo 0 > /proc/sys/vm/laptop_mode
            echo tsc > /sys/devices/system/clocksource/clocksource0/current_clocksource
      
            # enable logging
            service rsyslog start
      
            # ZiXEL nbg460n. Set maximum wifi speed
            if [ -f /etc/pm/802.11.bgn ]; then /etc/pm/802.11.bgn 1; fi
      
            # enable winbind
            if [ -f /etc/init.d/winbind ]; then  /etc/init.d/winbind start; fi
      
            # Powersave pci express
            echo performance > /sys/module/pcie_aspm/parameters/policy
            ;;
      
          true)  #batt_power
            # Set laptop disk write mode
            echo 5 > /proc/sys/vm/laptop_mode
            echo hpet > /sys/devices/system/clocksource/clocksource0/current_clocksource
            # disable logging
            service rsyslog stop
      
            # ZiXEL nbg460n. Set standard wifi speed
            if [ -f /etc/pm/802.11.bgn ]; then /etc/pm/802.11.bgn 0; fi
      
            # disable winbind
            if [ -f /etc/init.d/winbind ]; then  /etc/init.d/winbind stop ; fi
      
            echo powersave > /sys/module/pcie_aspm/parameters/policy
            ;;
        esac
      }
      
      aNotify()
      {
        case "$1" in
          false) #ac_power
            MSGH="AC" 
            MSGT="Maximum Performance Mode"
            MSGI="ac-adapter"
            ;;
          true)  #battery_power 
            MSGH="BATT" 
            MSGT="Battery Power Saving"
            MSGI="battery"
          ;;
        esac
      
        vUSER=`ps -C gnome-session -o user=` #find UID user who start gnome-session
        vPIDS=`pgrep -u $vUSER gnome-session` #find PID
        for PID in $vPIDS; do
          vDBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$PID/environ \
          | sed -e 's/DBUS_SESSION_BUS_ADDRESS=//')
          DBUS_SESSION_BUS_ADDRESS=$vDBUS_SESSION_BUS_ADDRESS DISPLAY=:0.0 sudo -u $vUSER notify-send "$MSGH" "$MSGT" -i "$MSGI"
        done
      }
      
      aLoadini()
      {
        if [ -e $INI ]; 
          then 
            echo "Restore Value"
            while read LINE
            do
              PARM=$(echo "$LINE" | awk '{print $1}')
              KEY=$(echo "$LINE" | awk '{print $2}')
              case $PARM in
                "AC_BRI")
                  vAC_BRI=$KEY
                  ;;
                "BAT_BRI")
                  vBAT_BRI=$KEY
                  ;;
                "USER")
                  vUSER=$KEY
                  ;;
                "PIDS")
                  vPIDS=$KEY
                  ;;
                "CONKY")
                  CONKY_RUN=$KEY
                  ;;
                "DBUS_SESSION_BUS_ADDRESS")
                  vDBUS_SESSION_BUS_ADDRESS=$KEY
                  ;;
              esac
              echo "$PARM $KEY"
            done < $INI
          else
            echo "Reset Value"
            # Conky is Running Check
            CONKY_RUN=$(ps -ef | grep -c /usr/bin/conky)
            ((CONKY_RUN-=1))
      
            vAC_BRI=15
            vBAT_BRI=8
            vUSER=""
            vPIDS=""
            vDBUS_SESSION_BUS_ADDRESS=""
        fi
      }
      
      aSaveini()
      {
        echo "AC_BRI $vAC_BRI" > $INI
        echo "BAT_BRI $vBAT_BRI" >> $INI
        echo "USER $vUSER" >> $INI
        echo "PIDS $vPIDS" >> $INI
        echo "CONKY $CONKY_RUN" >> $INI
        echo "DBUS_SESSION_BUS_ADDRESS $vDBUS_SESSION_BUS_ADDRESS" >> $INI
      }
      
      
      ##########################################################
      ## Apply settings
      ##
      aLoadini
      
      aCpu $1
      aUsb $1
      aI2c $1
      aSata $1
      aPci $1
      if [ $(hdparm -i /dev/sda | grep Model | awk '{print substr($2,1,3)}') = "SSD" ]; 
        then 
          aSsd $1
        else
          aHdd $1
      fi
      aI915 $1
      aWlan $1
      aLan $1
      aSnd $1
      aBt $1
      aWebcam $1
      aMemory $1
      aDaemons $1
      aBrightness $1
      aMisk $1
      aNotify $1
      
      aSaveini
      

      Сохраняем скрипт и закрываем редактор
    3. Подключаем скрипт к событиям power и sleep $ cd /usr/lib/pm-utils/power.d $ sudo chmod 755 99-savings.sh $ sudo install 99-savings.sh /etc/pm/sleep.d $ sudo install 99-savings.sh /etc/pm/power.d
    4. Проверяем
      Вытаскиваем провод источника питания и наблюдаем pop up сообщение, что компьютер перешел в режим сохранения энергии Вставяем провод источника питания и наблюдаем pop up сообщение, что компьютер перешел в режим максимального быстродействия

  2. Устанавливаем ядро 3.63.3.7
  3. У меня иногда с ядром 3.6 процессор переходит в Turbo mode и начинает сильно нагреваться. Powertop показывает частоту 3 GHz. htop не показывает никакого криминала. А процессоры находятся в состоянии powersave. Разбираюсь. Возможно это баг.
    Если у вас будет то же самое отпишите, плз.

    Можно не мудрствуя лукаво поставить из http://kernel.ubuntu.com/~kernel-ppa/mainline/v3.3.7-precise/ if [ ! -d "$HOME/kernel" ]; then mkdir $HOME/kernel; fi cd "$HOME/kernel" rm *.deb wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v3.3.7-precise/linux-headers-3.3.7-030307-generic_3.3.7-030307.201205211535_amd64.deb \ http://kernel.ubuntu.com/~kernel-ppa/mainline/v3.3.7-precise/linux-headers-3.3.7-030307_3.3.7-030307.201205211535_all.deb \ http://kernel.ubuntu.com/~kernel-ppa/mainline/v3.3.7-precise/linux-image-3.3.7-030307-generic_3.3.7-030307.201205211535_amd64.deb sudo dpkg -i *.deb

  4. Устанавливаем параметры загрузки Ubuntu в Grub
  5. В терминале с помощью редактора gedit $ sudo gedit /etc/default/grub Заменяем строку
    GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
    
    на
    GRUB_CMDLINE_LINUX_DEFAULT="quiet splash i915.i915_enable_rc6=1 i915.lvds_downclock=1 i915_enable_fbc=1 drm.vblankoffdelay=1 pcie_aspm=force reboot=pci"
    
    Обновляем grub $ sudo update-grub Перезагружаемся и проверяем энергопотребление.

  6. Success Story

  7. Евгений Попов прислал скриншот, на котором видно, что он смог снизить минимальное потребление до 4,77 Вт (Lenovo ThinkPad x220 4290RW1, Ubuntu 11.10).

    Участник с ником unr форума Ubuntu получил потребление около 5,5 Вт на ядре 3.2.5 (Lenovo ThinkPad x220 4290RW1, Ubuntu 11.10).


  8. Indicator

  9. Я самоуверенно дал программе название, которое уже присвоено другой утилите. К выходным переобзову и сделаю новый deb пакет.

    Не прошло и года, как я сделал простой индикатор, позволяющий выбирать (пока) один из двух режимов PowerSaving.

    Остальные пункты меню представляют собой заглушки. Надеюсь скоро их активизирую.
    Скачать индикатор можно по ссылке: powerman_0.1_amd64.deb
    Устанавливается, как обычный deb пакет. sudo dpkg --install powerman_0.1_amd64.deb После чего можно добавить запуск индикатора в Startup Applications:
    /usr/bin/powerman -t 10
    
    где -t 10 задает время задержки старта.

    И последним штрихом добавляем в sudoers команды, разрешающие запуск скрипта управления питанием без ввода пароля. sudo visudo
    # User alias specification
    # Change %axa to your Users Grup. Замените %axa на название группы, куда входит пользователь
    User_Alias USERS = %axa
    
    # Cmnd alias specification
    Cmnd_Alias PWR_SAVE =  /etc/pm/power.d/99-savings.sh
    
    # All User can run Power Saving script
    USERS ALL=NOPASSWD: PWR_SAVE
    

  10. Планы на развитие
  11. В планах убрать установку всех скриптов и модификацию управляющих файлов внутрь deb пакета.

Полезные ссылки:



03.10.2012 - добавил раздел установки индикатора
06.10.2012 - временно убрал раздел компиляции ядра и добавил раздел установки ядра 3.6 из ubuntu.kernel