From 6451a495637c6e3047a5a56573cffc6e3de9a515 Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Wed, 19 Oct 2011 10:56:04 +0200 Subject: Imported Upstream version 0.2+gitdfdad95 --- CMakeLists.txt | 171 ++ CMake_Uninstall.cmake.in | 26 + README | 80 + cmake/vala/FindVala.cmake | 65 + cmake/vala/ParseArguments.cmake | 36 + cmake/vala/ValaPrecompile.cmake | 175 ++ cmake/vala/ValaVersion.cmake | 96 + make.sh | 5 + resources/gnome-pie-indicator.svg | 770 +++++++ resources/gnome-pie.desktop | 7 + resources/gnome-pie.svg | 2896 ++++++++++++++++++++++++ resources/locale/compile-po.sh | 6 + resources/locale/de/LC_MESSAGES/de.po | 221 ++ resources/locale/de/LC_MESSAGES/gnomepie.mo | Bin 0 -> 3132 bytes resources/locale/gen-po.sh | 13 + resources/locale/gen-pot.sh | 22 + resources/locale/gnomepie.pot | 357 +++ resources/locale/pt-br/LC_MESSAGES/gnomepie.mo | Bin 0 -> 5633 bytes resources/locale/pt-br/LC_MESSAGES/pt-br.po | 301 +++ resources/themes/adwaita/arrow.svg | 121 + resources/themes/adwaita/icon_active.svg | 152 ++ resources/themes/adwaita/icon_inactive.svg | 152 ++ resources/themes/adwaita/ring.svg | 258 +++ resources/themes/adwaita/theme.xml | 27 + resources/themes/bright/arrow.svg | 121 + resources/themes/bright/gloss.svg | 156 ++ resources/themes/bright/icon_active.svg | 142 ++ resources/themes/bright/icon_inactive.svg | 142 ++ resources/themes/bright/ring.svg | 214 ++ resources/themes/bright/theme.xml | 29 + resources/themes/funky/bg.svg | 151 ++ resources/themes/funky/blue.svg | 148 ++ resources/themes/funky/caption.svg | 130 ++ resources/themes/funky/icon_bg.svg | 118 + resources/themes/funky/icon_fg.svg | 118 + resources/themes/funky/red.svg | 148 ++ resources/themes/funky/star.svg | 126 ++ resources/themes/funky/theme.xml | 38 + resources/themes/gloss/arrow.svg | 225 ++ resources/themes/gloss/glow_bg.svg | 140 ++ resources/themes/gloss/icon_bg.svg | 118 + resources/themes/gloss/icon_fg.svg | 214 ++ resources/themes/gloss/icon_fg_active.svg | 214 ++ resources/themes/gloss/icon_mask.svg | 118 + resources/themes/gloss/theme.xml | 34 + resources/themes/o-pie/arrow.svg | 115 + resources/themes/o-pie/ring.svg | 179 ++ resources/themes/o-pie/theme.xml | 24 + resources/themes/slim/bg.svg | 198 ++ resources/themes/slim/dot.svg | 125 + resources/themes/slim/theme.xml | 36 + resources/themes/unity/arrow.svg | 121 + resources/themes/unity/gloss.svg | 156 ++ resources/themes/unity/icon_active.svg | 142 ++ resources/themes/unity/icon_inactive.svg | 142 ++ resources/themes/unity/ring.svg | 214 ++ resources/themes/unity/theme.xml | 29 + src/CMakeLists.txt | 82 + src/actionGroups/actionGroup.vala | 75 + src/actionGroups/bookmarkGroup.vala | 148 ++ src/actionGroups/clipboardGroup.vala | 116 + src/actionGroups/devicesGroup.vala | 129 ++ src/actionGroups/groupRegistry.vala | 89 + src/actionGroups/menuGroup.vala | 254 +++ src/actionGroups/sessionGroup.vala | 68 + src/actions/action.vala | 77 + src/actions/actionRegistry.vala | 200 ++ src/actions/appAction.vala | 72 + src/actions/keyAction.vala | 77 + src/actions/pieAction.vala | 95 + src/actions/sigAction.vala | 63 + src/actions/uriAction.vala | 71 + src/deamon.vala | 175 ++ src/gui/about.vala | 43 + src/gui/cellRendererIcon.vala | 132 ++ src/gui/iconSelectWindow.vala | 349 +++ src/gui/indicator.vala | 160 ++ src/gui/pieList.vala | 1018 +++++++++ src/gui/preferences.vala | 338 +++ src/gui/themeList.vala | 95 + src/gui/tipViewer.vala | 172 ++ src/pies/defaultConfig.vala | 70 + src/pies/load.vala | 230 ++ src/pies/pie.vala | 96 + src/pies/pieManager.vala | 231 ++ src/pies/save.vala | 81 + src/renderers/centerRenderer.vala | 146 ++ src/renderers/pieRenderer.vala | 208 ++ src/renderers/pieWindow.vala | 263 +++ src/renderers/sliceRenderer.vala | 182 ++ src/themes/centerLayer.vala | 111 + src/themes/sliceLayer.vala | 65 + src/themes/theme.vala | 489 ++++ src/utilities/animatedValue.vala | 190 ++ src/utilities/bindingManager.vala | 196 ++ src/utilities/color.vala | 305 +++ src/utilities/config.vala | 202 ++ src/utilities/icon.vala | 102 + src/utilities/image.vala | 163 ++ src/utilities/key.vala | 139 ++ src/utilities/logger.vala | 194 ++ src/utilities/paths.vala | 211 ++ src/utilities/renderedText.vala | 110 + src/utilities/themedIcon.vala | 161 ++ vapi/appindicator-0.1.vapi | 94 + vapi/gee-1.0.vapi | 416 ++++ vapi/libgnome-menu-3.0.vapi | 93 + vapi/x11.vapi | 996 ++++++++ vapi/xtst.vapi | 60 + 109 files changed, 20184 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 CMake_Uninstall.cmake.in create mode 100644 README create mode 100644 cmake/vala/FindVala.cmake create mode 100644 cmake/vala/ParseArguments.cmake create mode 100644 cmake/vala/ValaPrecompile.cmake create mode 100644 cmake/vala/ValaVersion.cmake create mode 100755 make.sh create mode 100644 resources/gnome-pie-indicator.svg create mode 100755 resources/gnome-pie.desktop create mode 100644 resources/gnome-pie.svg create mode 100755 resources/locale/compile-po.sh create mode 100644 resources/locale/de/LC_MESSAGES/de.po create mode 100644 resources/locale/de/LC_MESSAGES/gnomepie.mo create mode 100755 resources/locale/gen-po.sh create mode 100755 resources/locale/gen-pot.sh create mode 100644 resources/locale/gnomepie.pot create mode 100644 resources/locale/pt-br/LC_MESSAGES/gnomepie.mo create mode 100644 resources/locale/pt-br/LC_MESSAGES/pt-br.po create mode 100644 resources/themes/adwaita/arrow.svg create mode 100644 resources/themes/adwaita/icon_active.svg create mode 100644 resources/themes/adwaita/icon_inactive.svg create mode 100644 resources/themes/adwaita/ring.svg create mode 100644 resources/themes/adwaita/theme.xml create mode 100644 resources/themes/bright/arrow.svg create mode 100644 resources/themes/bright/gloss.svg create mode 100644 resources/themes/bright/icon_active.svg create mode 100644 resources/themes/bright/icon_inactive.svg create mode 100644 resources/themes/bright/ring.svg create mode 100644 resources/themes/bright/theme.xml create mode 100644 resources/themes/funky/bg.svg create mode 100644 resources/themes/funky/blue.svg create mode 100644 resources/themes/funky/caption.svg create mode 100644 resources/themes/funky/icon_bg.svg create mode 100644 resources/themes/funky/icon_fg.svg create mode 100644 resources/themes/funky/red.svg create mode 100644 resources/themes/funky/star.svg create mode 100644 resources/themes/funky/theme.xml create mode 100644 resources/themes/gloss/arrow.svg create mode 100644 resources/themes/gloss/glow_bg.svg create mode 100644 resources/themes/gloss/icon_bg.svg create mode 100644 resources/themes/gloss/icon_fg.svg create mode 100644 resources/themes/gloss/icon_fg_active.svg create mode 100644 resources/themes/gloss/icon_mask.svg create mode 100644 resources/themes/gloss/theme.xml create mode 100644 resources/themes/o-pie/arrow.svg create mode 100644 resources/themes/o-pie/ring.svg create mode 100644 resources/themes/o-pie/theme.xml create mode 100644 resources/themes/slim/bg.svg create mode 100644 resources/themes/slim/dot.svg create mode 100644 resources/themes/slim/theme.xml create mode 100644 resources/themes/unity/arrow.svg create mode 100644 resources/themes/unity/gloss.svg create mode 100644 resources/themes/unity/icon_active.svg create mode 100644 resources/themes/unity/icon_inactive.svg create mode 100644 resources/themes/unity/ring.svg create mode 100644 resources/themes/unity/theme.xml create mode 100644 src/CMakeLists.txt create mode 100644 src/actionGroups/actionGroup.vala create mode 100644 src/actionGroups/bookmarkGroup.vala create mode 100644 src/actionGroups/clipboardGroup.vala create mode 100644 src/actionGroups/devicesGroup.vala create mode 100644 src/actionGroups/groupRegistry.vala create mode 100644 src/actionGroups/menuGroup.vala create mode 100644 src/actionGroups/sessionGroup.vala create mode 100644 src/actions/action.vala create mode 100644 src/actions/actionRegistry.vala create mode 100644 src/actions/appAction.vala create mode 100644 src/actions/keyAction.vala create mode 100644 src/actions/pieAction.vala create mode 100644 src/actions/sigAction.vala create mode 100644 src/actions/uriAction.vala create mode 100644 src/deamon.vala create mode 100644 src/gui/about.vala create mode 100644 src/gui/cellRendererIcon.vala create mode 100644 src/gui/iconSelectWindow.vala create mode 100644 src/gui/indicator.vala create mode 100644 src/gui/pieList.vala create mode 100644 src/gui/preferences.vala create mode 100644 src/gui/themeList.vala create mode 100644 src/gui/tipViewer.vala create mode 100644 src/pies/defaultConfig.vala create mode 100644 src/pies/load.vala create mode 100644 src/pies/pie.vala create mode 100644 src/pies/pieManager.vala create mode 100644 src/pies/save.vala create mode 100644 src/renderers/centerRenderer.vala create mode 100644 src/renderers/pieRenderer.vala create mode 100644 src/renderers/pieWindow.vala create mode 100644 src/renderers/sliceRenderer.vala create mode 100644 src/themes/centerLayer.vala create mode 100644 src/themes/sliceLayer.vala create mode 100644 src/themes/theme.vala create mode 100644 src/utilities/animatedValue.vala create mode 100644 src/utilities/bindingManager.vala create mode 100644 src/utilities/color.vala create mode 100644 src/utilities/config.vala create mode 100644 src/utilities/icon.vala create mode 100644 src/utilities/image.vala create mode 100644 src/utilities/key.vala create mode 100644 src/utilities/logger.vala create mode 100644 src/utilities/paths.vala create mode 100644 src/utilities/renderedText.vala create mode 100644 src/utilities/themedIcon.vala create mode 100644 vapi/appindicator-0.1.vapi create mode 100644 vapi/gee-1.0.vapi create mode 100644 vapi/libgnome-menu-3.0.vapi create mode 100644 vapi/x11.vapi create mode 100644 vapi/xtst.vapi diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..fadea59 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,171 @@ +################################################################ +# Project Gnome-Pie +################################################################ + +project("gnomepie" C) + +cmake_minimum_required(VERSION 2.6) + +# Location where cmake first looks for modules. +list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/vala) + +################################################################ +# Find Vala +################################################################ + +include(ValaPrecompile) +include(ValaVersion) + +find_package(Vala) +ensure_vala_version("0.11.0" MINIMUM) + +################################################################ +# Configure and find libraries +################################################################ + +find_package(PkgConfig) +pkg_check_modules(GIO REQUIRED gio-unix-2.0) +pkg_check_modules(GTK REQUIRED gtk+-2.0) +pkg_check_modules(CAIRO REQUIRED cairo) +pkg_check_modules(GEE REQUIRED gee-1.0) +pkg_check_modules(X11 REQUIRED x11) +pkg_check_modules(INDICATOR appindicator-0.1) +pkg_check_modules(XML REQUIRED libxml-2.0) +pkg_check_modules(XTST REQUIRED xtst) +pkg_check_modules(UNIQUE REQUIRED unique-1.0) +pkg_check_modules(GMENU3 libgnome-menu-3.0) + +find_library(M_LIB m) + +set(CFLAGS + ${GIO_CFLAGS} + ${GTK_CFLAGS} ${GTK_CFLAGS_OTHER} + ${CAIRO_CFLAGS} ${CAIRO_CFLAGS_OTHER} + ${GEE_CFLAGS} ${CAIRO_CFLAGS_OTHER} + ${X11_CFLAGS} ${X11_CFLAGS_OTHER} + -DGMENU_I_KNOW_THIS_IS_UNSTABLE + -DGETTEXT_PACKAGE="gnomepie" + -s -O3 +) + +if (${GMENU3_FOUND}) + LIST(APPEND CFLAGS -DHAVE_GMENU_3) +else (${GMENU3_FOUND}) + pkg_check_modules(GMENU REQUIRED libgnome-menu) +endif (${GMENU3_FOUND}) + +if (${INDICATOR_FOUND}) + LIST(APPEND CFLAGS -DHAVE_APPINDICATOR) +endif (${INDICATOR_FOUND}) + +add_definitions(${CFLAGS}) + +set(LIBS + ${GIO_LIBRARIES} + ${GTK_LIBRARIES} + ${CAIRO_LIBRARIES} + ${GEE_LIBRARIES} + ${INDICATOR_LIBRARIES} + ${XML_LIBRARIES} + ${XTST_LIBRARIES} + ${GMENU_LIBRARIES} + ${GMENU3_LIBRARIES} + ${UNIQUE_LIBRARIES} + ${X11_LIBRARIES} + ${M_LIB} +) +link_libraries(${LIBS}) + +set(LIB_PATHS + ${GIO_LIBRARY_DIRS} + ${GTK_LIBRARY_DIRS} + ${CAIRO_LIBRARY_DIRS} + ${GEE_LIBRARY_DIRS} + ${INDICATOR_LIBRARY_DIRS} + ${XML_LIBRARY_DIRS} + ${XTST_LIBRARY_DIRS} + ${GMENU_LIBRARY_DIRS} + ${GMENU3_LIBRARY_DIRS} + ${UNIQUE_LIBRARY_DIRS} + ${X11_LIBRARY_DIRS} +) +link_directories(${LIB_PATHS}) + +set(INCLUDE_PATHS + ${GIO_INCLUDE_DIRS} + ${GTK_INCLUDE_DIRS} + ${CAIRO_INCLUDE_DIRS} + ${GEE_INCLUDE_DIRS} + ${INDICATOR_INCLUDE_DIRS} + ${XML_INCLUDE_DIRS} + ${XTST_INCLUDE_DIRS} + ${GMENU_INCLUDE_DIRS} + ${GMENU3_INCLUDE_DIRS} + ${UNIQUE_INCLUDE_DIRS} + ${X11_INCLUDE_DIRS} +) +include_directories(${INCLUDE_PATHS}) + +################################################################ +# Add executable +################################################################ + +set(EXECUTABLE_OUTPUT_PATH ${gnomepie_SOURCE_DIR}) + +set(VALA_PKGS + gtk+-2.0 + gdk-x11-2.0 + cairo + gee-1.0 + x11 + gio-unix-2.0 + posix + libxml-2.0 + xtst + unique-1.0 +) + +if (${INDICATOR_FOUND}) + LIST(APPEND VALA_PKGS appindicator-0.1) +endif (${INDICATOR_FOUND}) + +if (${GMENU3_FOUND}) + LIST(APPEND VALA_PKGS libgnome-menu-3.0) +else (${GMENU3_FOUND}) + LIST(APPEND VALA_PKGS libgnome-menu) +endif (${GMENU3_FOUND}) + +add_subdirectory(src) + +################################################################ +# Add uninstall option +################################################################ + +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/CMake_Uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/CMake_Uninstall.cmake" + IMMEDIATE @ONLY) + +add_custom_target(uninstall + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/CMake_Uninstall.cmake) + +################################################################ +# Summary +################################################################ + +message( "" ) +message( "Summary:" ) +message( " EXECUTABLE_OUTPUT_PATH = ${EXECUTABLE_OUTPUT_PATH}" ) +message( " VALA_EXECUTABLE = ${VALA_EXECUTABLE}" ) +message( "Libs:" ) +message( " GTK_LIBRARIES = ${GTK_LIBRARIES}" ) +message( " CAIRO_LIBRARIES = ${CAIRO_LIBRARIES}" ) +message( " GEE_LIBRARIES = ${GEE_LIBRARIES}" ) +message( " INDICATOR_LIBRARIES = ${INDICATOR_LIBRARIES}" ) +message( " XML_LIBRARIES = ${XML_LIBRARIES}" ) +message( " XTST_LIBRARIES = ${XTST_LIBRARIES}" ) +message( " GMENU_LIBRARIES = ${GMENU_LIBRARIES}" ) +message( " GMENU3_LIBRARIES = ${GMENU3_LIBRARIES}" ) +message( " UNIQUE_LIBRARIES = ${UNIQUE_LIBRARIES}" ) +message( " X11_LIBRARIES = ${X11_LIBRARIES}" ) +message( "" ) diff --git a/CMake_Uninstall.cmake.in b/CMake_Uninstall.cmake.in new file mode 100644 index 0000000..6ccb93f --- /dev/null +++ b/CMake_Uninstall.cmake.in @@ -0,0 +1,26 @@ +################################################################ +# Project Gnome-Pie --- uninstall script +################################################################ + +if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") + +foreach (file ${files}) + message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + if (EXISTS "$ENV{DESTDIR}${file}") + execute_process( + COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" + OUTPUT_VARIABLE rm_out + RESULT_VARIABLE rm_retval + ) + if(NOT ${rm_retval} EQUAL 0) + message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + endif (NOT ${rm_retval} EQUAL 0) + else (EXISTS "$ENV{DESTDIR}${file}") + message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") + endif (EXISTS "$ENV{DESTDIR}${file}") +endforeach(file) diff --git a/README b/README new file mode 100644 index 0000000..81ac7a4 --- /dev/null +++ b/README @@ -0,0 +1,80 @@ +#################################################################### +# Gnome-Pie # +#################################################################### + +This is an experimantal attempt to create a visual application +launcher for the Gnome Desktop. + +Homepage: http://gnome-pie.simonschneegans.de + +It is inspired by the an addon written for the game World of Warcraft. +(http://go-hero.net/opie/) + +#################################################################### +# About this Branch # +#################################################################### + +This is the master Branch of Gnome-Pie. A recent "stable" version +will be in here. + +#################################################################### +# PPA # +#################################################################### + +There is a PPA with a recent version of Gnome-Pie. If you simply +want to test it, it's very easy to install: + +sudo add-apt-repository ppa:simonschneegans/testing +sudo apt-get update +sudo apt-get install gnome-pie + +#################################################################### +# Compiling # +#################################################################### + +First of all, install all dependancies: + +sudo apt-get install libgtk2.0-dev libcairo2-dev libappindicator-dev + libgee-dev libxml2-dev libxtst-dev + libgnome-menu-dev valac cmake libunique-dev + +Then build and launch Gnome-Pie by typing: + +./make.sh + +#################################################################### +# Usage # +#################################################################### + +Now you may launch it by Pressing A to open up a default +Pie with your default applications. There are some other Pies +defined --- just open up the configuration dialog by activating the +appropriate entry in the appindicator menu or by launching gnome-pie +for a second time. There you may configure the Pies to suit your +needs. + +You can open Pies not only by presing their key stroke. +Alternatively you may open any Pie by invoking gnome-pie --open 123 +where 123 is the ID of the desired Pie (which is displayed in the +configuration dialog). + +#################################################################### +# License # +#################################################################### + +Copyright (C) 2011 Simon Schneegans + +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 3 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, see . + + diff --git a/cmake/vala/FindVala.cmake b/cmake/vala/FindVala.cmake new file mode 100644 index 0000000..aa3a6e7 --- /dev/null +++ b/cmake/vala/FindVala.cmake @@ -0,0 +1,65 @@ +## +# Copyright 2009-2010 Jakob Westhoff. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY JAKOB WESTHOFF ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL JAKOB WESTHOFF OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# The views and conclusions contained in the software and documentation are those +# of the authors and should not be interpreted as representing official policies, +# either expressed or implied, of Jakob Westhoff +## + +## +# Find module for the Vala compiler (valac) +# +# This module determines wheter a Vala compiler is installed on the current +# system and where its executable is. +# +# Call the module using "find_package(Vala) from within your CMakeLists.txt. +# +# The following variables will be set after an invocation: +# +# VALA_FOUND Whether the vala compiler has been found or not +# VALA_EXECUTABLE Full path to the valac executable if it has been found +# VALA_VERSION Version number of the available valac +## + + +# Search for the valac executable in the usual system paths. +find_program(VALA_EXECUTABLE + NAMES valac) + +# Handle the QUIETLY and REQUIRED arguments, which may be given to the find call. +# Furthermore set VALA_FOUND to TRUE if Vala has been found (aka. +# VALA_EXECUTABLE is set) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Vala DEFAULT_MSG VALA_EXECUTABLE) + +mark_as_advanced(VALA_EXECUTABLE) + +# Determine the valac version +if(VALA_FOUND) + execute_process(COMMAND ${VALA_EXECUTABLE} "--version" + OUTPUT_VARIABLE "VALA_VERSION") + string(REPLACE "Vala" "" "VALA_VERSION" ${VALA_VERSION}) + string(STRIP ${VALA_VERSION} "VALA_VERSION") +endif(VALA_FOUND) diff --git a/cmake/vala/ParseArguments.cmake b/cmake/vala/ParseArguments.cmake new file mode 100644 index 0000000..717c0f5 --- /dev/null +++ b/cmake/vala/ParseArguments.cmake @@ -0,0 +1,36 @@ +## +# This is a helper Macro to parse optional arguments in Macros/Functions +# It has been taken from the public CMake wiki. +# See http://www.cmake.org/Wiki/CMakeMacroParseArguments for documentation and +# licensing. +## +macro(parse_arguments prefix arg_names option_names) + set(DEFAULT_ARGS) + foreach(arg_name ${arg_names}) + set(${prefix}_${arg_name}) + endforeach(arg_name) + foreach(option ${option_names}) + set(${prefix}_${option} FALSE) + endforeach(option) + + set(current_arg_name DEFAULT_ARGS) + set(current_arg_list) + foreach(arg ${ARGN}) + set(larg_names ${arg_names}) + list(FIND larg_names "${arg}" is_arg_name) + if(is_arg_name GREATER -1) + set(${prefix}_${current_arg_name} ${current_arg_list}) + set(current_arg_name ${arg}) + set(current_arg_list) + else(is_arg_name GREATER -1) + set(loption_names ${option_names}) + list(FIND loption_names "${arg}" is_option) + if(is_option GREATER -1) + set(${prefix}_${arg} TRUE) + else(is_option GREATER -1) + set(current_arg_list ${current_arg_list} ${arg}) + endif(is_option GREATER -1) + endif(is_arg_name GREATER -1) + endforeach(arg) + set(${prefix}_${current_arg_name} ${current_arg_list}) +endmacro(parse_arguments) diff --git a/cmake/vala/ValaPrecompile.cmake b/cmake/vala/ValaPrecompile.cmake new file mode 100644 index 0000000..19c4739 --- /dev/null +++ b/cmake/vala/ValaPrecompile.cmake @@ -0,0 +1,175 @@ +## +# Copyright 2009-2010 Jakob Westhoff. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY JAKOB WESTHOFF ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL JAKOB WESTHOFF OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# The views and conclusions contained in the software and documentation are those +# of the authors and should not be interpreted as representing official policies, +# either expressed or implied, of Jakob Westhoff +## + +include(ParseArguments) +find_package(Vala REQUIRED) + +## +# Compile vala files to their c equivalents for further processing. +# +# The "vala_precompile" macro takes care of calling the valac executable on the +# given source to produce c files which can then be processed further using +# default cmake functions. +# +# The first parameter provided is a variable, which will be filled with a list +# of c files outputted by the vala compiler. This list can than be used in +# conjuction with functions like "add_executable" or others to create the +# neccessary compile rules with CMake. +# +# The initial variable is followed by a list of .vala files to be compiled. +# Please take care to add every vala file belonging to the currently compiled +# project or library as Vala will otherwise not be able to resolve all +# dependencies. +# +# The following sections may be specified afterwards to provide certain options +# to the vala compiler: +# +# PACKAGES +# A list of vala packages/libraries to be used during the compile cycle. The +# package names are exactly the same, as they would be passed to the valac +# "--pkg=" option. +# +# OPTIONS +# A list of optional options to be passed to the valac executable. This can be +# used to pass "--thread" for example to enable multi-threading support. +# +# CUSTOM_VAPIS +# A list of custom vapi files to be included for compilation. This can be +# useful to include freshly created vala libraries without having to install +# them in the system. +# +# GENERATE_VAPI +# Pass all the needed flags to the compiler to create an internal vapi for +# the compiled library. The provided name will be used for this and a +# .vapi file will be created. +# +# GENERATE_HEADER +# Let the compiler generate a header file for the compiled code. There will +# be a header file as well as an internal header file being generated called +# .h and _internal.h +# +# The following call is a simple example to the vala_precompile macro showing +# an example to every of the optional sections: +# +# vala_precompile(VALA_C +# source1.vala +# source2.vala +# source3.vala +# PACKAGES +# gtk+-2.0 +# gio-1.0 +# posix +# DIRECTORY +# gen +# OPTIONS +# --thread +# CUSTOM_VAPIS +# some_vapi.vapi +# GENERATE_VAPI +# myvapi +# GENERATE_HEADER +# myheader +# ) +# +# Most important is the variable VALA_C which will contain all the generated c +# file names after the call. +## + +macro(vala_precompile output) + parse_arguments(ARGS "PACKAGES;OPTIONS;DIRECTORY;GENERATE_HEADER;GENERATE_VAPI;CUSTOM_VAPIS" "" ${ARGN}) + if(ARGS_DIRECTORY) + set(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${ARGS_DIRECTORY}) + else(ARGS_DIRECTORY) + set(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + endif(ARGS_DIRECTORY) + include_directories(${DIRECTORY}) + set(vala_pkg_opts "") + foreach(pkg ${ARGS_PACKAGES}) + list(APPEND vala_pkg_opts "--pkg=${pkg}") + endforeach(pkg ${ARGS_PACKAGES}) + set(in_files "") + set(out_files "") + set(${output} "") + foreach(src ${ARGS_DEFAULT_ARGS}) + list(APPEND in_files "${CMAKE_CURRENT_SOURCE_DIR}/${src}") + string(REPLACE ".vala" ".c" src ${src}) + string(REPLACE ".gs" ".c" src ${src}) + set(out_file "${DIRECTORY}/${src}") + list(APPEND out_files "${DIRECTORY}/${src}") + list(APPEND ${output} ${out_file}) + endforeach(src ${ARGS_DEFAULT_ARGS}) + + set(custom_vapi_arguments "") + if(ARGS_CUSTOM_VAPIS) + foreach(vapi ${ARGS_CUSTOM_VAPIS}) + if(${vapi} MATCHES ${CMAKE_SOURCE_DIR} OR ${vapi} MATCHES ${CMAKE_BINARY_DIR}) + list(APPEND custom_vapi_arguments ${vapi}) + else (${vapi} MATCHES ${CMAKE_SOURCE_DIR} OR ${vapi} MATCHES ${CMAKE_BINARY_DIR}) + list(APPEND custom_vapi_arguments ${CMAKE_CURRENT_SOURCE_DIR}/${vapi}) + endif(${vapi} MATCHES ${CMAKE_SOURCE_DIR} OR ${vapi} MATCHES ${CMAKE_BINARY_DIR}) + endforeach(vapi ${ARGS_CUSTOM_VAPIS}) + endif(ARGS_CUSTOM_VAPIS) + + set(vapi_arguments "") + if(ARGS_GENERATE_VAPI) + list(APPEND out_files "${DIRECTORY}/${ARGS_GENERATE_VAPI}.vapi") + set(vapi_arguments "--internal-vapi=${ARGS_GENERATE_VAPI}.vapi") + + # Header and internal header is needed to generate internal vapi + if (NOT ARGS_GENERATE_HEADER) + set(ARGS_GENERATE_HEADER ${ARGS_GENERATE_VAPI}) + endif(NOT ARGS_GENERATE_HEADER) + endif(ARGS_GENERATE_VAPI) + + set(header_arguments "") + if(ARGS_GENERATE_HEADER) + list(APPEND out_files "${DIRECTORY}/${ARGS_GENERATE_HEADER}.h") + list(APPEND out_files "${DIRECTORY}/${ARGS_GENERATE_HEADER}_internal.h") + list(APPEND header_arguments "--header=${DIRECTORY}/${ARGS_GENERATE_HEADER}.h") + list(APPEND header_arguments "--internal-header=${DIRECTORY}/${ARGS_GENERATE_HEADER}_internal.h") + endif(ARGS_GENERATE_HEADER) + + add_custom_command(OUTPUT ${out_files} + COMMAND + ${VALA_EXECUTABLE} + ARGS + "-C" + ${header_arguments} + ${vapi_arguments} + "-b" ${CMAKE_CURRENT_SOURCE_DIR} + "-d" ${DIRECTORY} + ${vala_pkg_opts} + ${ARGS_OPTIONS} + ${in_files} + ${custom_vapi_arguments} + DEPENDS + ${in_files} + ${ARGS_CUSTOM_VAPIS} + ) +endmacro(vala_precompile) diff --git a/cmake/vala/ValaVersion.cmake b/cmake/vala/ValaVersion.cmake new file mode 100644 index 0000000..3fff193 --- /dev/null +++ b/cmake/vala/ValaVersion.cmake @@ -0,0 +1,96 @@ +## +# Copyright 2009-2010 Jakob Westhoff. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY JAKOB WESTHOFF ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL JAKOB WESTHOFF OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# The views and conclusions contained in the software and documentation are those +# of the authors and should not be interpreted as representing official policies, +# either expressed or implied, of Jakob Westhoff +## + +include(ParseArguments) +find_package(Vala REQUIRED) + +## +# Ensure a certain valac version is available +# +# The initial argument is the version to check for +# +# It may be followed by a optional parameter to specifiy a version range. The +# following options are valid: +# +# EXACT +# Vala needs to be available in the exact version given +# +# MINIMUM +# The provided version is the minimum version. Therefore Vala needs to be +# available in the given version or any higher version +# +# MAXIMUM +# The provided version is the maximum. Therefore Vala needs to be available +# in the given version or any version older than this +# +# If no option is specified the version will be treated as a minimal version. +## +macro(ensure_vala_version version) + parse_arguments(ARGS "" "MINIMUM;MAXIMUM;EXACT" ${ARGN}) + set(compare_message "") + set(error_message "") + if(ARGS_MINIMUM) + set(compare_message "a minimum ") + set(error_message "or greater ") + elseif(ARGS_MAXIMUM) + set(compare_message "a maximum ") + set(error_message "or less ") + endif(ARGS_MINIMUM) + + message(STATUS + "checking for ${compare_message}Vala version of ${version}" + ) + + unset(version_accepted) + + # MINIMUM is the default if no option is specified + if(ARGS_EXACT) + if(${VALA_VERSION} VERSION_EQUAL ${version} ) + set(version_accepted TRUE) + endif(${VALA_VERSION} VERSION_EQUAL ${version}) + elseif(ARGS_MAXIMUM) + if(${VALA_VERSION} VERSION_LESS ${version} OR ${VALA_VERSION} VERSION_EQUAL ${version}) + set(version_accepted TRUE) + endif(${VALA_VERSION} VERSION_LESS ${version} OR ${VALA_VERSION} VERSION_EQUAL ${version}) + else(ARGS_MAXIMUM) + if(${VALA_VERSION} VERSION_GREATER ${version} OR ${VALA_VERSION} VERSION_EQUAL ${version}) + set(version_accepted TRUE) + endif(${VALA_VERSION} VERSION_GREATER ${version} OR ${VALA_VERSION} VERSION_EQUAL ${version}) + endif(ARGS_EXACT) + + if (NOT version_accepted) + message(FATAL_ERROR + "Vala version ${version} ${error_message}is required." + ) + endif(NOT version_accepted) + + message(STATUS + " found Vala, version ${VALA_VERSION}" + ) +endmacro(ensure_vala_version) diff --git a/make.sh b/make.sh new file mode 100755 index 0000000..0bd7ca8 --- /dev/null +++ b/make.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +mkdir build + +cd build; cmake ..; make && ( cd .. ) diff --git a/resources/gnome-pie-indicator.svg b/resources/gnome-pie-indicator.svg new file mode 100644 index 0000000..bfeb5bd --- /dev/null +++ b/resources/gnome-pie-indicator.svg @@ -0,0 +1,770 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/gnome-pie.desktop b/resources/gnome-pie.desktop new file mode 100755 index 0000000..ae5811d --- /dev/null +++ b/resources/gnome-pie.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Type=Application +Name=Gnome-Pie +Comment=Cakes don't lie. +Exec=gnome-pie +Icon=gnome-pie +Categories=GNOME;Utility; diff --git a/resources/gnome-pie.svg b/resources/gnome-pie.svg new file mode 100644 index 0000000..c001a21 --- /dev/null +++ b/resources/gnome-pie.svg @@ -0,0 +1,2896 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/locale/compile-po.sh b/resources/locale/compile-po.sh new file mode 100755 index 0000000..6b201de --- /dev/null +++ b/resources/locale/compile-po.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +for d in `ls -d */` +do + msgfmt -c -v $d/LC_MESSAGES/*.po -o $d/LC_MESSAGES/gnomepie.mo +done diff --git a/resources/locale/de/LC_MESSAGES/de.po b/resources/locale/de/LC_MESSAGES/de.po new file mode 100644 index 0000000..3426769 --- /dev/null +++ b/resources/locale/de/LC_MESSAGES/de.po @@ -0,0 +1,221 @@ +# German translations for gnomepie package. +# Copyright (C) 2011 Simon Schneegans +# This file is distributed under the same license as the gnomepie package. +# Simon Schneegans , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: gnomepie 0.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-08-25 21:04+0200\n" +"PO-Revision-Date: 2011-08-25 21:04+0200\n" +"Last-Translator: Simon Schneegans \n" +"Language-Team: German\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: ../../src/actions/keyAction.vala:24 ../../src/settings/pieList.vala:73 +msgid "Press key stroke" +msgstr "Tastenkombination" + +#: ../../src/actions/appAction.vala:24 ../../src/settings/pieList.vala:72 +msgid "Launch application" +msgstr "Programm ausführen" + +#: ../../src/actions/action.vala:88 +msgid "Trash" +msgstr "Müll" + +#: ../../src/actions/uriAction.vala:24 ../../src/settings/pieList.vala:75 +msgid "Open URI" +msgstr "URI öffnen" + +#: ../../src/actions/pieAction.vala:24 ../../src/settings/pieList.vala:74 +msgid "Open Pie" +msgstr "Pie öffnen" + +#: ../../src/settings/preferences.vala:26 +msgid "Gnome-Pie - Settings" +msgstr "Gnome-Pie - Einstellungen" + +#: ../../src/settings/preferences.vala:49 +msgid "Behavior" +msgstr "Verhalten" + +#: ../../src/settings/preferences.vala:59 +msgid "Startup on Login" +msgstr "Beim Anmelden automatisch ausführen" + +#: ../../src/settings/preferences.vala:65 +msgid "Show Indicator" +msgstr "Benachrichtigungssymbol anzeigen" + +#: ../../src/settings/preferences.vala:71 +msgid "Open Pies at Mouse" +msgstr "Pies an der Maus öffnen" + +#: ../../src/settings/preferences.vala:77 +msgid "Click to activate a Slice" +msgstr "Klicken um Slices zu aktivieren" + +#: ../../src/settings/preferences.vala:86 +msgid "Global Scale" +msgstr "Skalierungsfaktor" + +#: ../../src/settings/preferences.vala:123 +msgid "Themes" +msgstr "Themen" + +#: ../../src/settings/preferences.vala:141 +msgid "General" +msgstr "Allgemein" + +#: ../../src/settings/preferences.vala:146 +msgid "Pies" +msgstr "Pies" + +#: ../../src/settings/preferences.vala:170 +msgid "" +"You can right-click in the list\n" +"for adding or removing entries." +msgstr "" +"Zum Löschen und Hinzufügen von Einträgen kannst \n" +"du mit der rechten Maustaste in die Liste klicken." + +#: ../../src/settings/themeList.vala:75 +msgid "by" +msgstr "von" + +#: ../../src/settings/iconChooserWindow.vala:79 +msgid "Choose an Icon" +msgstr "Wähle ein Symbol" + +#: ../../src/settings/iconChooserWindow.vala:101 +msgid "All icons" +msgstr "Alle Symbole" + +#: ../../src/settings/iconChooserWindow.vala:102 +msgid "Applications" +msgstr "Anwendungen" + +#: ../../src/settings/iconChooserWindow.vala:103 +msgid "Actions" +msgstr "Aktionen" + +#: ../../src/settings/iconChooserWindow.vala:104 +msgid "Places" +msgstr "Orte" + +#: ../../src/settings/iconChooserWindow.vala:105 +msgid "File types" +msgstr "Dateitypen" + +#: ../../src/settings/iconChooserWindow.vala:106 +msgid "Emotes" +msgstr "Smilies" + +#: ../../src/settings/iconChooserWindow.vala:107 +msgid "Miscellaneous" +msgstr "Sonstige" + +#: ../../src/settings/pieList.vala:56 +#: ../../src/actionGroups/bookmarkGroup.vala:23 +msgid "Bookmarks" +msgstr "Lesezeichen" + +#: ../../src/settings/pieList.vala:57 +#: ../../src/actionGroups/devicesGroup.vala:23 +msgid "Devices" +msgstr "Laufwerke" + +#: ../../src/settings/pieList.vala:58 ../../src/actionGroups/menuGroup.vala:25 +msgid "Main menu" +msgstr "Hauptmenü" + +#: ../../src/settings/pieList.vala:59 +#: ../../src/actionGroups/sessionGroup.vala:23 +msgid "Session Control" +msgstr "Sitzung" + +#: ../../src/settings/pieList.vala:76 ../../src/settings/pieList.vala:738 +msgid "Slice group" +msgstr "Slice-Gruppe" + +#: ../../src/settings/pieList.vala:119 +msgid "Icon" +msgstr "Symbol" + +#: ../../src/settings/pieList.vala:181 +msgid "Command" +msgstr "Kommando" + +#: ../../src/settings/pieList.vala:261 ../../src/settings/pieList.vala:601 +#: ../../src/settings/pieList.vala:753 +#: ../../src/system/bindingManager.vala:118 +msgid "Not bound" +msgstr "Nicht zugewiesen" + +#: ../../src/settings/pieList.vala:326 +msgid "Action type" +msgstr "Slice-Typ" + +#: ../../src/settings/pieList.vala:388 +msgid "Name" +msgstr "Name" + +#: ../../src/settings/pieList.vala:423 +msgid "Add new Pie" +msgstr "Pie hinzufügen" + +#: ../../src/settings/pieList.vala:428 +msgid "Add new Slice" +msgstr "Slice hinzufügen" + +#: ../../src/settings/pieList.vala:436 +msgid "Delete" +msgstr "Eintrag löschen" + +#: ../../src/settings/pieList.vala:517 +msgid "New Pie" +msgstr "Neuer Pie" + +#: ../../src/settings/pieList.vala:562 +msgid "New Action" +msgstr "Neue Slice" + +#: ../../src/settings/pieList.vala:576 +msgid "You have to select a Pie to add a Slice to!" +msgstr "Es muss ein Pie ausgewählt sein, zu dem eine Slice hinzugefügt werden soll!" + +#: ../../src/settings/pieList.vala:623 +msgid "You have to select a Pie or a Slice to delete!" +msgstr "Es muss etwas ausgewählt sein, das gelöscht werden soll!" + +#: ../../src/settings/pieList.vala:633 +msgid "" +"Do you really want to delete the selected Pie with all contained Slices?" +msgstr "" +"Soll dieser Pie wirklich mit allen Slices gelöscht werden?" + +#: ../../src/settings/pieList.vala:666 +msgid "Do you really want to delete the selected Slice?" +msgstr "Soll die ausgewählte Slice wirklich gelöscht werden?" + +#: ../../src/actionGroups/sessionGroup.vala:29 +msgid "Shutdown" +msgstr "Herunterfahren" + +#: ../../src/actionGroups/sessionGroup.vala:32 +msgid "Logout" +msgstr "Ausloggen" + +#: ../../src/actionGroups/sessionGroup.vala:35 +msgid "Reboot" +msgstr "Neustarten" + +#: ../../src/actionGroups/devicesGroup.vala:44 +msgid "Root" +msgstr "Dateisystem" diff --git a/resources/locale/de/LC_MESSAGES/gnomepie.mo b/resources/locale/de/LC_MESSAGES/gnomepie.mo new file mode 100644 index 0000000..622b2ee Binary files /dev/null and b/resources/locale/de/LC_MESSAGES/gnomepie.mo differ diff --git a/resources/locale/gen-po.sh b/resources/locale/gen-po.sh new file mode 100755 index 0000000..cecc4c9 --- /dev/null +++ b/resources/locale/gen-po.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +echo "Insert your locale:"; +read locale; + +if [ "$locale" == "" ] +then + echo "No locale inserted! Aborting..."; + exit 1 +fi + +mkdir -p $locale/LC_MESSAGES +msginit --locale=$locale --input=gnomepie.pot --output=$locale/LC_MESSAGES/$locale.po diff --git a/resources/locale/gen-pot.sh b/resources/locale/gen-pot.sh new file mode 100755 index 0000000..65acff3 --- /dev/null +++ b/resources/locale/gen-pot.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# Searches trough all vala files of Gnome-Pie and generates +# a gnomepie.pot for strings which need to be translated. + +filelist=$( find ../../src/ -name '*.vala' -printf "%h/%f " ) + +domain="gnomepie" +version="0.1" +copyright="Simon Schneegans " + +xgettext --package-name $domain \ + --package-version $version \ + --default-domain $domain \ + --output $domain.pot \ + --copyright-holder="$copyright" \ + -k_ \ + -L C# \ + $filelist + +sed --in-place $domain.pot --expression='s/CHARSET/UTF-8/' + diff --git a/resources/locale/gnomepie.pot b/resources/locale/gnomepie.pot new file mode 100644 index 0000000..871ef0e --- /dev/null +++ b/resources/locale/gnomepie.pot @@ -0,0 +1,357 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR Simon Schneegans +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: gnomepie 0.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-11 15:55-0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../../src/actions/keyAction.vala:33 +msgid "Press key stroke" +msgstr "" + +#: ../../src/actions/pieAction.vala:33 +msgid "Open Pie" +msgstr "" + +#: ../../src/actions/appAction.vala:33 +msgid "Launch application" +msgstr "" + +#: ../../src/actions/uriAction.vala:33 +msgid "Open URI" +msgstr "" + +#: ../../src/actions/actionRegistry.vala:107 +msgid "Trash" +msgstr "" + +#: ../../src/utilities/bindingManager.vala:150 ../../src/gui/pieList.vala:278 +#: ../../src/gui/pieList.vala:660 ../../src/gui/pieList.vala:818 +msgid "Not bound" +msgstr "" + +#: ../../src/pies/defaultConfig.vala:29 +msgid "Multimedia" +msgstr "" + +#: ../../src/pies/defaultConfig.vala:30 +msgid "Next Track" +msgstr "" + +#: ../../src/pies/defaultConfig.vala:31 +msgid "Stop" +msgstr "" + +#: ../../src/pies/defaultConfig.vala:32 +msgid "Previous Track" +msgstr "" + +#: ../../src/pies/defaultConfig.vala:33 +msgid "Play/Pause" +msgstr "" + +#: ../../src/pies/defaultConfig.vala:36 +#: ../../src/gui/iconSelectWindow.vala:119 +msgid "Applications" +msgstr "" + +#: ../../src/pies/defaultConfig.vala:45 +#: ../../src/actionGroups/bookmarkGroup.vala:35 +msgid "Bookmarks" +msgstr "" + +#: ../../src/pies/defaultConfig.vala:50 +msgid "Session" +msgstr "" + +#: ../../src/pies/defaultConfig.vala:54 +msgid "Main Menu" +msgstr "" + +#: ../../src/pies/defaultConfig.vala:58 +msgid "Window" +msgstr "" + +#: ../../src/pies/defaultConfig.vala:59 +msgid "Scale" +msgstr "" + +#: ../../src/pies/defaultConfig.vala:60 +msgid "Minimize" +msgstr "" + +#: ../../src/pies/defaultConfig.vala:61 +msgid "Close" +msgstr "" + +#: ../../src/pies/defaultConfig.vala:62 +msgid "Maximize" +msgstr "" + +#: ../../src/pies/defaultConfig.vala:63 +msgid "Restore" +msgstr "" + +#: ../../src/gui/preferences.vala:32 +msgid "Gnome-Pie - Settings" +msgstr "" + +#: ../../src/gui/preferences.vala:55 +msgid "Behavior" +msgstr "" + +#: ../../src/gui/preferences.vala:65 +msgid "Startup on Login" +msgstr "" + +#: ../../src/gui/preferences.vala:66 +msgid "If checked, Gnome-Pie will start when you log in." +msgstr "" + +#: ../../src/gui/preferences.vala:72 +msgid "Show Indicator" +msgstr "" + +#: ../../src/gui/preferences.vala:73 +msgid "" +"If checked, an indicator for easy access of the settings menu is shown in " +"your panel." +msgstr "" + +#: ../../src/gui/preferences.vala:79 +msgid "Open Pies at Mouse" +msgstr "" + +#: ../../src/gui/preferences.vala:80 +msgid "" +"If checked, pies will open at your pointer. Otherwise they'll pop up in the " +"middle of the screen." +msgstr "" + +#: ../../src/gui/preferences.vala:86 +msgid "Turbo mode" +msgstr "" + +#: ../../src/gui/preferences.vala:87 +msgid "" +"If checked, the pie closes when its keystroke is released. The currently " +"hovered slice gets executed. This allows very fast selection but disables " +"keyboard navigating." +msgstr "" + +#: ../../src/gui/preferences.vala:96 +msgid "Global Scale" +msgstr "" + +#: ../../src/gui/preferences.vala:133 +msgid "Themes" +msgstr "" + +#: ../../src/gui/preferences.vala:151 +msgid "General" +msgstr "" + +#: ../../src/gui/preferences.vala:156 +msgid "Pies" +msgstr "" + +#: ../../src/gui/preferences.vala:180 +msgid "You can right-click in the list for adding or removing entries." +msgstr "" + +#: ../../src/gui/preferences.vala:181 +msgid "" +"You can reset Gnome-Pie to its default options with the terminal command " +"\"gnome-pie --reset\"." +msgstr "" + +#: ../../src/gui/preferences.vala:182 +msgid "" +"The radiobutton at the beginning of each slice-line indicates the " +"QuickAction of the pie." +msgstr "" + +#: ../../src/gui/preferences.vala:183 +msgid "Pies can be opened with the terminal command \"gnome-pie --open=ID\"." +msgstr "" + +#: ../../src/gui/preferences.vala:184 +msgid "Feel free to visit Gnome-Pie's homepage at %s!" +msgstr "" + +#: ../../src/gui/preferences.vala:185 +msgid "You can drag'n'drop applications from your main menu to the list above." +msgstr "" + +#: ../../src/gui/preferences.vala:186 +msgid "If you want to give some feedback, please write an e-mail to %s!" +msgstr "" + +#: ../../src/gui/preferences.vala:187 +msgid "" +"You may drag'n'drop URLs and bookmarks from your internet browser to the " +"list above." +msgstr "" + +#: ../../src/gui/preferences.vala:188 +msgid "Bugs can be reported at %s!" +msgstr "" + +#: ../../src/gui/preferences.vala:189 +msgid "" +"It's possible to drag'n'drop files and folders from your file browser to the " +"list above." +msgstr "" + +#: ../../src/gui/preferences.vala:198 +msgid "Moves the selected Slice down" +msgstr "" + +#: ../../src/gui/preferences.vala:210 +msgid "Moves the selected Slice up" +msgstr "" + +#: ../../src/gui/pieList.vala:88 ../../src/gui/pieList.vala:803 +msgid "Slice group" +msgstr "" + +#: ../../src/gui/pieList.vala:134 +msgid "Icon" +msgstr "" + +#: ../../src/gui/pieList.vala:199 +msgid "Command" +msgstr "" + +#: ../../src/gui/pieList.vala:343 +msgid "Pie-ID / Action type" +msgstr "" + +#: ../../src/gui/pieList.vala:403 +msgid "Name" +msgstr "" + +#: ../../src/gui/pieList.vala:446 +msgid "Add new Pie" +msgstr "" + +#: ../../src/gui/pieList.vala:451 +msgid "Add new Slice" +msgstr "" + +#: ../../src/gui/pieList.vala:459 +msgid "Delete" +msgstr "" + +#: ../../src/gui/pieList.vala:574 +msgid "New Pie" +msgstr "" + +#: ../../src/gui/pieList.vala:620 +msgid "New Action" +msgstr "" + +#: ../../src/gui/pieList.vala:634 +msgid "You have to select a Pie to add a Slice to!" +msgstr "" + +#: ../../src/gui/pieList.vala:683 +msgid "You have to select a Pie or a Slice to delete!" +msgstr "" + +#: ../../src/gui/pieList.vala:694 +msgid "" +"Do you really want to delete the selected Pie with all contained Slices?" +msgstr "" + +#: ../../src/gui/pieList.vala:728 +msgid "Do you really want to delete the selected Slice?" +msgstr "" + +#: ../../src/gui/themeList.vala:88 +msgid "by" +msgstr "" + +#: ../../src/gui/iconSelectWindow.vala:91 +msgid "Choose an Icon" +msgstr "" + +#: ../../src/gui/iconSelectWindow.vala:118 +msgid "All icons" +msgstr "" + +#: ../../src/gui/iconSelectWindow.vala:120 +msgid "Actions" +msgstr "" + +#: ../../src/gui/iconSelectWindow.vala:121 +msgid "Places" +msgstr "" + +#: ../../src/gui/iconSelectWindow.vala:122 +msgid "File types" +msgstr "" + +#: ../../src/gui/iconSelectWindow.vala:123 +msgid "Emotes" +msgstr "" + +#: ../../src/gui/iconSelectWindow.vala:124 +msgid "Miscellaneous" +msgstr "" + +#: ../../src/gui/iconSelectWindow.vala:192 +msgid "Icon Theme" +msgstr "" + +#: ../../src/gui/iconSelectWindow.vala:200 +msgid "All supported image formats" +msgstr "" + +#: ../../src/gui/iconSelectWindow.vala:217 +msgid "Custom Icon" +msgstr "" + +#: ../../src/actionGroups/devicesGroup.vala:34 +msgid "Devices" +msgstr "" + +#: ../../src/actionGroups/devicesGroup.vala:82 +msgid "Root" +msgstr "" + +#: ../../src/actionGroups/sessionGroup.vala:34 +msgid "Session Control" +msgstr "" + +#: ../../src/actionGroups/sessionGroup.vala:52 +msgid "Shutdown" +msgstr "" + +#: ../../src/actionGroups/sessionGroup.vala:55 +msgid "Logout" +msgstr "" + +#: ../../src/actionGroups/sessionGroup.vala:58 +msgid "Reboot" +msgstr "" + +#: ../../src/actionGroups/menuGroup.vala:33 +msgid "Main menu" +msgstr "" + +#: ../../src/actionGroups/clipboardGroup.vala:62 +msgid "Clipboard" +msgstr "" diff --git a/resources/locale/pt-br/LC_MESSAGES/gnomepie.mo b/resources/locale/pt-br/LC_MESSAGES/gnomepie.mo new file mode 100644 index 0000000..7c0c5d9 Binary files /dev/null and b/resources/locale/pt-br/LC_MESSAGES/gnomepie.mo differ diff --git a/resources/locale/pt-br/LC_MESSAGES/pt-br.po b/resources/locale/pt-br/LC_MESSAGES/pt-br.po new file mode 100644 index 0000000..b192fc0 --- /dev/null +++ b/resources/locale/pt-br/LC_MESSAGES/pt-br.po @@ -0,0 +1,301 @@ +# Language pt-br translations for gnomepie package. +# Copyright (C) 2011 Simon Schneegans +# This file is distributed under the same license as the gnomepie package. +# Magnun Leno , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: gnomepie 0.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-11 15:55-0300\n" +"PO-Revision-Date: 2011-10-11 15:55-0300\n" +"Last-Translator: Magnun Leno \n" +"Language-Team: Language pt-br\n" +"Language: pt-br\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../../src/actions/keyAction.vala:33 +msgid "Press key stroke" +msgstr "Pressione qualquer tecla" + +#: ../../src/actions/pieAction.vala:33 +msgid "Open Pie" +msgstr "Abrir menu" + +#: ../../src/actions/appAction.vala:33 +msgid "Launch application" +msgstr "Lançar aplicação" + +#: ../../src/actions/uriAction.vala:33 +msgid "Open URI" +msgstr "Abrir URL" + +#: ../../src/actions/actionRegistry.vala:107 +msgid "Trash" +msgstr "Remover" + +#: ../../src/pies/defaultConfig.vala:62 +msgid "Maximize" +msgstr "Maximizar" + +#: ../../src/pies/defaultConfig.vala:63 +msgid "Restore" +msgstr "" + +#: ../../src/gui/preferences.vala:32 +msgid "Gnome-Pie - Settings" +msgstr "Gnome-Pie - Configurações" + +#: ../../src/gui/preferences.vala:55 +msgid "Behavior" +msgstr "Comportamento" + +#: ../../src/gui/preferences.vala:65 +msgid "Startup on Login" +msgstr "Iniciar durante o Login" + +#: ../../src/gui/preferences.vala:66 +msgid "If checked, Gnome-Pie will start when you log in." +msgstr "Se marcado, o Gnome-Pie irá iniciar durante o login." + +#: ../../src/gui/preferences.vala:72 +msgid "Show Indicator" +msgstr "Mostrar Indicador" + +#: ../../src/gui/preferences.vala:73 +msgid "" +"If checked, an indicator for easy access of the settings menu is shown in " +"your panel." +msgstr "" +"Se marcado, um indicador para facilitar o acesso às configurações estará " +"disponível em seu painel." + +#: ../../src/gui/preferences.vala:79 +msgid "Open Pies at Mouse" +msgstr "Abrir Menus sobre o Mouse" + +#: ../../src/gui/preferences.vala:86 +msgid "Turbo mode" +msgstr "Modo Turbo" + +#: ../../src/gui/preferences.vala:87 +msgid "" +"If checked, the pie closes when its keystroke is released. The currently " +"hovered slice gets executed. This allows very fast selection but disables " +"keyboard navigating." +msgstr "" +"Se marcado, o menu se fechará quando a combinação de teclas for liberada. A opção que estiver " +"sobre o cursor será executada. Essa opção possibilita uma uma seleção rápida mas desativa " +"a navegação pelo teclado." + +#: ../../src/gui/preferences.vala:96 +msgid "Global Scale" +msgstr "Escalonamento Global" + +#: ../../src/gui/preferences.vala:133 +msgid "Themes" +msgstr "Temas" + +#: ../../src/gui/preferences.vala:151 +msgid "General" +msgstr "Geral" + +#: ../../src/gui/preferences.vala:156 +msgid "Pies" +msgstr "Menus" + +#: ../../src/gui/preferences.vala:180 +msgid "You can right-click in the list for adding or removing entries." +msgstr "Você pode clicar com o botão direito sobre a lista para adicioná-las ou removê-las." + +#: ../../src/gui/preferences.vala:181 +msgid "" +"You can reset Gnome-Pie to its default options with the terminal command " +"\"gnome-pie --reset\"." +msgstr "" +"Você pode voltar o Gnome-Pie para suas configurações padrão usando o comando de terminal " +"\"gnome-pie --reset\"." + +#: ../../src/gui/preferences.vala:182 +msgid "" +"The radiobutton at the beginning of each slice-line indicates the " +"QuickAction of the pie." +msgstr "" +"O botão de seleção no início de cada Opção indica a " +"Ação Rápida vinculada ao Menu." + +#: ../../src/gui/preferences.vala:183 +msgid "Pies can be opened with the terminal command \"gnome-pie --open=ID\"." +msgstr "Menus podem ser abertos através do terminal com o comando \"gnome-pie --open=ID\"." + +#: ../../src/gui/preferences.vala:184 +msgid "Feel free to visit Gnome-Pie's homepage at %s!" +msgstr "Sinta-se a vontade para visitar o site do Gnome-Pie em %s" + +#: ../../src/gui/preferences.vala:185 +msgid "You can drag'n'drop applications from your main menu to the list above." +msgstr "Você pode arrastar aplicações do seu menu principal para a lista acima." + +#: ../../src/gui/preferences.vala:186 +msgid "If you want to give some feedback, please write an e-mail to %s!" +msgstr "Se você quiser enviar algum feedback, por favor escreva um e-mail para %s!" + +#: ../../src/gui/preferences.vala:187 +msgid "" +"You may drag'n'drop URLs and bookmarks from your internet browser to the " +"list above." +msgstr "" +"Você pode arrastar URLs e Favoritos do seu navegador predileto para " +"a lista acima." + +#: ../../src/gui/preferences.vala:188 +msgid "Bugs can be reported at %s!" +msgstr "Defeitos podem ser informados em %s!" + +#: ../../src/gui/preferences.vala:189 +msgid "" +"It's possible to drag'n'drop files and folders from your file browser to the " +"list above." +msgstr "" +"É possível arrastar arquivos e pastas do seu navegador para dentro da " +"lista acima." + +#: ../../src/gui/preferences.vala:198 +msgid "Moves the selected Slice down" +msgstr "Move a Opção selecionada para baixo" + +#: ../../src/gui/preferences.vala:210 +msgid "Moves the selected Slice up" +msgstr "Move a Opção selecionada para cima" + +#: ../../src/gui/pieList.vala:88 ../../src/gui/pieList.vala:803 +msgid "Slice group" +msgstr "Grupo de Opções" + +#: ../../src/gui/pieList.vala:134 +msgid "Icon" +msgstr "Ícone" + +#: ../../src/gui/pieList.vala:199 +msgid "Command" +msgstr "Comando" + +#: ../../src/gui/pieList.vala:343 +msgid "Pie-ID / Action type" +msgstr "ID-Opção / Tipo de Ação" + +#: ../../src/gui/pieList.vala:403 +msgid "Name" +msgstr "Nome" + +#: ../../src/gui/pieList.vala:446 +msgid "Add new Pie" +msgstr "Adicionar novo Menu" + +#: ../../src/gui/pieList.vala:451 +msgid "Add new Slice" +msgstr "Adicionar nova Opção" + +#: ../../src/gui/pieList.vala:459 +msgid "Delete" +msgstr "Deletar" + +#: ../../src/gui/pieList.vala:574 +msgid "New Pie" +msgstr "Novo Menu" + +#: ../../src/gui/pieList.vala:620 +msgid "New Action" +msgstr "Nova Ação" + +#: ../../src/gui/pieList.vala:634 +msgid "You have to select a Pie to add a Slice to!" +msgstr "Você tem que selecionar um Menu para poder adicionar uma Opção" + +#: ../../src/gui/pieList.vala:683 +msgid "You have to select a Pie or a Slice to delete!" +msgstr "Para remover você precisa selecionar um Menu ou uma Opção" + +#: ../../src/gui/pieList.vala:694 +msgid "" +"Do you really want to delete the selected Pie with all contained Slices?" +msgstr "" +"Você realmente deseja excluir o Menu selecionado e todas as suas Opções?" + +#: ../../src/gui/pieList.vala:728 +msgid "Do you really want to delete the selected Slice?" +msgstr "Você realmente deseja excluir a Opção selecionada?" + +#: ../../src/gui/iconSelectWindow.vala:91 +msgid "Choose an Icon" +msgstr "Escolha um Ícone" + +#: ../../src/gui/iconSelectWindow.vala:118 +msgid "All icons" +msgstr "Todos os ícones" + +#: ../../src/gui/iconSelectWindow.vala:120 +msgid "Actions" +msgstr "Ações" + +#: ../../src/gui/iconSelectWindow.vala:121 +msgid "Places" +msgstr "Lugares" + +#: ../../src/gui/iconSelectWindow.vala:122 +msgid "File types" +msgstr "Tipos de arquivos" + +#: ../../src/gui/iconSelectWindow.vala:123 +msgid "Emotes" +msgstr "Emotes" + +#: ../../src/gui/iconSelectWindow.vala:124 +msgid "Miscellaneous" +msgstr "Diversos" + +#: ../../src/gui/iconSelectWindow.vala:192 +msgid "Icon Theme" +msgstr "Tema de Ícones" + +#: ../../src/gui/iconSelectWindow.vala:200 +msgid "All supported image formats" +msgstr "Todos os tipos de imagem suportados" + +#: ../../src/gui/iconSelectWindow.vala:217 +msgid "Custom Icon" +msgstr "Outros Ícones" + +#: ../../src/actionGroups/devicesGroup.vala:34 +msgid "Devices" +msgstr "Dispositivos" + +#: ../../src/actionGroups/devicesGroup.vala:82 +msgid "Root" +msgstr "Raiz" + +#: ../../src/actionGroups/sessionGroup.vala:34 +msgid "Session Control" +msgstr "Controle de Sessão" + +#: ../../src/actionGroups/sessionGroup.vala:52 +msgid "Shutdown" +msgstr "Desligar" + +#: ../../src/actionGroups/sessionGroup.vala:55 +msgid "Logout" +msgstr "Logout" + +#: ../../src/actionGroups/sessionGroup.vala:58 +msgid "Reboot" +msgstr "Reboot" + +#: ../../src/actionGroups/menuGroup.vala:33 +msgid "Main menu" +msgstr "Menu Principal" + +#: ../../src/actionGroups/clipboardGroup.vala:62 +msgid "Clipboard" +msgstr "Clipboard" diff --git a/resources/themes/adwaita/arrow.svg b/resources/themes/adwaita/arrow.svg new file mode 100644 index 0000000..4b81a6d --- /dev/null +++ b/resources/themes/adwaita/arrow.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/themes/adwaita/icon_active.svg b/resources/themes/adwaita/icon_active.svg new file mode 100644 index 0000000..8393747 --- /dev/null +++ b/resources/themes/adwaita/icon_active.svg @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/resources/themes/adwaita/icon_inactive.svg b/resources/themes/adwaita/icon_inactive.svg new file mode 100644 index 0000000..1120dc9 --- /dev/null +++ b/resources/themes/adwaita/icon_inactive.svg @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/resources/themes/adwaita/ring.svg b/resources/themes/adwaita/ring.svg new file mode 100644 index 0000000..acc7c61 --- /dev/null +++ b/resources/themes/adwaita/ring.svg @@ -0,0 +1,258 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/resources/themes/adwaita/theme.xml b/resources/themes/adwaita/theme.xml new file mode 100644 index 0000000..25b18ff --- /dev/null +++ b/resources/themes/adwaita/theme.xml @@ -0,0 +1,27 @@ + + + + +
+ + +
+ + + + + + + + + + + +
+
+ diff --git a/resources/themes/bright/arrow.svg b/resources/themes/bright/arrow.svg new file mode 100644 index 0000000..4b81a6d --- /dev/null +++ b/resources/themes/bright/arrow.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/themes/bright/gloss.svg b/resources/themes/bright/gloss.svg new file mode 100644 index 0000000..60a795f --- /dev/null +++ b/resources/themes/bright/gloss.svg @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/resources/themes/bright/icon_active.svg b/resources/themes/bright/icon_active.svg new file mode 100644 index 0000000..79593ab --- /dev/null +++ b/resources/themes/bright/icon_active.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/themes/bright/icon_inactive.svg b/resources/themes/bright/icon_inactive.svg new file mode 100644 index 0000000..a16fdcf --- /dev/null +++ b/resources/themes/bright/icon_inactive.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/themes/bright/ring.svg b/resources/themes/bright/ring.svg new file mode 100644 index 0000000..f11ccbd --- /dev/null +++ b/resources/themes/bright/ring.svg @@ -0,0 +1,214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/resources/themes/bright/theme.xml b/resources/themes/bright/theme.xml new file mode 100644 index 0000000..511e3e1 --- /dev/null +++ b/resources/themes/bright/theme.xml @@ -0,0 +1,29 @@ + + + + +
+ + +
+ + + + + + + + + + + + + +
+
+ diff --git a/resources/themes/funky/bg.svg b/resources/themes/funky/bg.svg new file mode 100644 index 0000000..1f5b6e3 --- /dev/null +++ b/resources/themes/funky/bg.svg @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/themes/funky/blue.svg b/resources/themes/funky/blue.svg new file mode 100644 index 0000000..159516c --- /dev/null +++ b/resources/themes/funky/blue.svg @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/resources/themes/funky/caption.svg b/resources/themes/funky/caption.svg new file mode 100644 index 0000000..ebdc75d --- /dev/null +++ b/resources/themes/funky/caption.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/themes/funky/icon_bg.svg b/resources/themes/funky/icon_bg.svg new file mode 100644 index 0000000..4c37253 --- /dev/null +++ b/resources/themes/funky/icon_bg.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/themes/funky/icon_fg.svg b/resources/themes/funky/icon_fg.svg new file mode 100644 index 0000000..f2f8207 --- /dev/null +++ b/resources/themes/funky/icon_fg.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/themes/funky/red.svg b/resources/themes/funky/red.svg new file mode 100644 index 0000000..9932ebb --- /dev/null +++ b/resources/themes/funky/red.svg @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/resources/themes/funky/star.svg b/resources/themes/funky/star.svg new file mode 100644 index 0000000..4faac80 --- /dev/null +++ b/resources/themes/funky/star.svg @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/themes/funky/theme.xml b/resources/themes/funky/theme.xml new file mode 100644 index 0000000..a953089 --- /dev/null +++ b/resources/themes/funky/theme.xml @@ -0,0 +1,38 @@ + + + + +
+ + + + + +
+ + + + + + + + + + + + + +
+
+ diff --git a/resources/themes/gloss/arrow.svg b/resources/themes/gloss/arrow.svg new file mode 100644 index 0000000..10cd599 --- /dev/null +++ b/resources/themes/gloss/arrow.svg @@ -0,0 +1,225 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/themes/gloss/glow_bg.svg b/resources/themes/gloss/glow_bg.svg new file mode 100644 index 0000000..a4bb460 --- /dev/null +++ b/resources/themes/gloss/glow_bg.svg @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/themes/gloss/icon_bg.svg b/resources/themes/gloss/icon_bg.svg new file mode 100644 index 0000000..cbbda42 --- /dev/null +++ b/resources/themes/gloss/icon_bg.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/themes/gloss/icon_fg.svg b/resources/themes/gloss/icon_fg.svg new file mode 100644 index 0000000..53b57a0 --- /dev/null +++ b/resources/themes/gloss/icon_fg.svg @@ -0,0 +1,214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/resources/themes/gloss/icon_fg_active.svg b/resources/themes/gloss/icon_fg_active.svg new file mode 100644 index 0000000..9483a68 --- /dev/null +++ b/resources/themes/gloss/icon_fg_active.svg @@ -0,0 +1,214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/resources/themes/gloss/icon_mask.svg b/resources/themes/gloss/icon_mask.svg new file mode 100644 index 0000000..cbbda42 --- /dev/null +++ b/resources/themes/gloss/icon_mask.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/themes/gloss/theme.xml b/resources/themes/gloss/theme.xml new file mode 100644 index 0000000..efc20e0 --- /dev/null +++ b/resources/themes/gloss/theme.xml @@ -0,0 +1,34 @@ + + + + +
+ + + + +
+ + + + + + + + + + + + + +
+
+ diff --git a/resources/themes/o-pie/arrow.svg b/resources/themes/o-pie/arrow.svg new file mode 100644 index 0000000..94b457c --- /dev/null +++ b/resources/themes/o-pie/arrow.svg @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/themes/o-pie/ring.svg b/resources/themes/o-pie/ring.svg new file mode 100644 index 0000000..6a6975f --- /dev/null +++ b/resources/themes/o-pie/ring.svg @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/resources/themes/o-pie/theme.xml b/resources/themes/o-pie/theme.xml new file mode 100644 index 0000000..19d4101 --- /dev/null +++ b/resources/themes/o-pie/theme.xml @@ -0,0 +1,24 @@ + + + + +
+ + +
+ + + + + + + + +
+
+ diff --git a/resources/themes/slim/bg.svg b/resources/themes/slim/bg.svg new file mode 100644 index 0000000..3496355 --- /dev/null +++ b/resources/themes/slim/bg.svg @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/themes/slim/dot.svg b/resources/themes/slim/dot.svg new file mode 100644 index 0000000..b5945c6 --- /dev/null +++ b/resources/themes/slim/dot.svg @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/themes/slim/theme.xml b/resources/themes/slim/theme.xml new file mode 100644 index 0000000..91b5a96 --- /dev/null +++ b/resources/themes/slim/theme.xml @@ -0,0 +1,36 @@ + + + + +
+ + + + + + +
+ + + + + + + + +
+
+ diff --git a/resources/themes/unity/arrow.svg b/resources/themes/unity/arrow.svg new file mode 100644 index 0000000..4b81a6d --- /dev/null +++ b/resources/themes/unity/arrow.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/themes/unity/gloss.svg b/resources/themes/unity/gloss.svg new file mode 100644 index 0000000..60a795f --- /dev/null +++ b/resources/themes/unity/gloss.svg @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/resources/themes/unity/icon_active.svg b/resources/themes/unity/icon_active.svg new file mode 100644 index 0000000..79593ab --- /dev/null +++ b/resources/themes/unity/icon_active.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/themes/unity/icon_inactive.svg b/resources/themes/unity/icon_inactive.svg new file mode 100644 index 0000000..e5ad950 --- /dev/null +++ b/resources/themes/unity/icon_inactive.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/themes/unity/ring.svg b/resources/themes/unity/ring.svg new file mode 100644 index 0000000..1fb2dcd --- /dev/null +++ b/resources/themes/unity/ring.svg @@ -0,0 +1,214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/resources/themes/unity/theme.xml b/resources/themes/unity/theme.xml new file mode 100644 index 0000000..9718753 --- /dev/null +++ b/resources/themes/unity/theme.xml @@ -0,0 +1,29 @@ + + + + +
+ + +
+ + + + + + + + + + + + + +
+
+ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..b3b8ed3 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,82 @@ +################################################################ +# Actually compile the executable +################################################################ + +# determine source and header files +file(GLOB VALA_SRC RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.vala */*.vala) + +if (${INDICATOR_FOUND}) + SET(DEFINES --define HAVE_APPINDICATOR) +endif(${INDICATOR_FOUND}) + +if (${GMENU3_FOUND}) + LIST(APPEND DEFINES --define HAVE_GMENU_3) +endif (${GMENU3_FOUND}) + +# use valac to compile sources to c files +vala_precompile( + VALA_C + ${VALA_SRC} + PACKAGES + ${VALA_PKGS} + OPTIONS + --vapidir=${CMAKE_SOURCE_DIR}/vapi/ + --thread + ${DEFINES} +) + +# compile c-sources +add_executable(gnome-pie ${VALA_C}) + +# install executable +install( + TARGETS + gnome-pie + RUNTIME DESTINATION + ${CMAKE_INSTALL_PREFIX}/bin +) + +# install credits +install( + FILES + ${CMAKE_SOURCE_DIR}/README + DESTINATION + ${CMAKE_INSTALL_PREFIX}/share/doc/gnome-pie +) + +# install locales +install( + DIRECTORY + ${CMAKE_SOURCE_DIR}/resources/locale + DESTINATION + ${CMAKE_INSTALL_PREFIX}/share + PATTERN *.po EXCLUDE + PATTERN *.pot EXCLUDE + PATTERN *.sh EXCLUDE +) + +# install themes +install( + DIRECTORY + ${CMAKE_SOURCE_DIR}/resources/themes + DESTINATION + ${CMAKE_INSTALL_PREFIX}/share/gnome-pie +) + +# install icons +install( + FILES + ${CMAKE_SOURCE_DIR}/resources/gnome-pie.svg + ${CMAKE_SOURCE_DIR}/resources/gnome-pie-indicator.svg + DESTINATION + ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps +) + +# desktop file +install( + FILES + ${CMAKE_SOURCE_DIR}/resources/gnome-pie.desktop + DESTINATION + ${CMAKE_INSTALL_PREFIX}/share/applications +) + diff --git a/src/actionGroups/actionGroup.vala b/src/actionGroups/actionGroup.vala new file mode 100644 index 0000000..a6b52ff --- /dev/null +++ b/src/actionGroups/actionGroup.vala @@ -0,0 +1,75 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +// A base class storing a set of Actions. Derived classes may define +// how these Actions are created. This base class serves for custom +// actions, defined by the user. +///////////////////////////////////////////////////////////////////////// + +public class ActionGroup : GLib.Object { + + ///////////////////////////////////////////////////////////////////// + /// A list of all stored actions. + ///////////////////////////////////////////////////////////////////// + + public Gee.ArrayList actions { get; private set; } + + ///////////////////////////////////////////////////////////////////// + /// The ID of the pie to which this group is attached. + ///////////////////////////////////////////////////////////////////// + + public string parent_id { get; construct set; } + + ///////////////////////////////////////////////////////////////////// + /// C'tor, initializes all members. + ///////////////////////////////////////////////////////////////////// + + public ActionGroup(string parent_id) { + GLib.Object(parent_id : parent_id); + } + + construct { + this.actions = new Gee.ArrayList(); + } + + ///////////////////////////////////////////////////////////////////// + /// This one is called, when the ActionGroup is deleted. + ///////////////////////////////////////////////////////////////////// + + public virtual void on_remove() {} + + ///////////////////////////////////////////////////////////////////// + /// Adds a new Action to the group. + ///////////////////////////////////////////////////////////////////// + + public void add_action(Action new_action) { + this.actions.add(new_action); + } + + ///////////////////////////////////////////////////////////////////// + /// Removes all Actions from the group. + ///////////////////////////////////////////////////////////////////// + + public void delete_all() { + actions.clear(); + } +} + +} diff --git a/src/actionGroups/bookmarkGroup.vala b/src/actionGroups/bookmarkGroup.vala new file mode 100644 index 0000000..f4ba66e --- /dev/null +++ b/src/actionGroups/bookmarkGroup.vala @@ -0,0 +1,148 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A group of Actions, which represent the users gtk-bookmarks, his home +/// directory, desktop and trash. It stay up-to-date, even if the +/// bookmarks change. +///////////////////////////////////////////////////////////////////////// + +public class BookmarkGroup : ActionGroup { + + ///////////////////////////////////////////////////////////////////// + /// Used to register this type of ActionGroup. It sets the display + /// name for this ActionGroup, it's icon name and the string used in + /// the pies.conf file for this kind of ActionGroups. + ///////////////////////////////////////////////////////////////////// + + public static void register(out string name, out string icon, out string settings_name) { + name = _("Bookmarks"); + icon = "user-bookmarks"; + settings_name = "bookmarks"; + } + + ///////////////////////////////////////////////////////////////////// + /// Two members needed to avoid useless, frequent changes of the + /// stored Actions. + ///////////////////////////////////////////////////////////////////// + + private bool changing = false; + private bool changed_again = false; + + ///////////////////////////////////////////////////////////////////// + /// C'tor, initializes all members. + ///////////////////////////////////////////////////////////////////// + + public BookmarkGroup(string parent_id) { + GLib.Object(parent_id : parent_id); + } + + ///////////////////////////////////////////////////////////////////// + /// Construct block loads the bookmarks of the user and adds a file + /// monitor in order to update the BookmarkGroup when the bookmarks + /// of the user change. + ///////////////////////////////////////////////////////////////////// + + construct { + this.load(); + + // add monitor + var bookmark_file = GLib.File.new_for_path( + GLib.Environment.get_home_dir()).get_child(".gtk-bookmarks"); + + if (bookmark_file.query_exists()) { + try { + var monitor = bookmark_file.monitor(GLib.FileMonitorFlags.NONE); + monitor.changed.connect(this.reload); + } catch (GLib.Error e) { + warning(e.message); + } + } + } + + ///////////////////////////////////////////////////////////////////// + /// Adds Actions for each gtk-bookmark of the user and for his home + /// folder, desktop and trash. + ///////////////////////////////////////////////////////////////////// + + private void load() { + // add home folder + this.add_action(ActionRegistry.new_for_uri("file://" + GLib.Environment.get_home_dir())); + + // add .gtk-bookmarks + var bookmark_file = GLib.File.new_for_path( + GLib.Environment.get_home_dir()).get_child(".gtk-bookmarks"); + + if (!bookmark_file.query_exists()) { + warning("Failed to find file \".gtk-bookmarks\"!"); + return; + } + + try { + var dis = new DataInputStream(bookmark_file.read()); + string line; + while ((line = dis.read_line(null)) != null) { + var parts = line.split(" "); + + string uri = parts[0]; + string name = parts[1]; + + this.add_action(ActionRegistry.new_for_uri(uri, name)); + } + } catch (Error e) { + error ("%s", e.message); + } + + // add trash + this.add_action(ActionRegistry.new_for_uri("trash:///")); + + // add desktop + this.add_action(ActionRegistry.new_for_uri("file://" + GLib.Environment.get_user_special_dir(GLib.UserDirectory.DESKTOP))); + } + + ///////////////////////////////////////////////////////////////////// + /// Reloads all Bookmarks. Is called when the user's gtk-bookmarks + /// file changes. + ///////////////////////////////////////////////////////////////////// + + private void reload() { + // avoid too frequent changes... + if (!this.changing) { + this.changing = true; + Timeout.add(200, () => { + if (this.changed_again) { + this.changed_again = false; + return true; + } + + // reload + message("Bookmarks changed..."); + this.delete_all(); + this.load(); + + this.changing = false; + return false; + }); + } else { + this.changed_again = true; + } + } +} + +} diff --git a/src/actionGroups/clipboardGroup.vala b/src/actionGroups/clipboardGroup.vala new file mode 100644 index 0000000..0e95b65 --- /dev/null +++ b/src/actionGroups/clipboardGroup.vala @@ -0,0 +1,116 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// This Group keeps a history of the last used Clipboard entries. +///////////////////////////////////////////////////////////////////////// + +public class ClipboardGroup : ActionGroup { + + ///////////////////////////////////////////////////////////////////// + /// + ///////////////////////////////////////////////////////////////////// + + private class ClipboardItem : GLib.Object { + + public string name { get; private set; } + public string icon { get; private set; } + + private Gtk.SelectionData contents; + + public ClipboardItem(Gtk.SelectionData contents) { + this.contents = contents.copy(); + this.name = this.contents.get_text() ?? ""; + this.icon = "edit-paste"; + } + + public void paste() { + debug(name); + } + } + + public ClipboardGroup(string parent_id) { + GLib.Object(parent_id : parent_id); + } + + ///////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////// + /// Used to register this type of ActionGroup. It sets the display + /// name for this ActionGroup, it's icon name and the string used in + /// the pies.conf file for this kind of ActionGroups. + ///////////////////////////////////////////////////////////////////// + + public static void register(out string name, out string icon, out string settings_name) { + name = _("Clipboard"); + icon = "edit-paste"; + settings_name = "clipboard"; + } + + ///////////////////////////////////////////////////////////////////// + /// The clipboard to be monitored. + ///////////////////////////////////////////////////////////////////// + + private Gtk.Clipboard clipboard; + + + ///////////////////////////////////////////////////////////////////// + /// The maximum remembered items of the clipboard. + ///////////////////////////////////////////////////////////////////// + + private const int max_items = 6; + + private Gee.ArrayList items; + + construct { + this.items = new Gee.ArrayList(); + this.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD); + this.clipboard.owner_change.connect(this.on_change); + } + + private void on_change() { + if (this.clipboard.wait_is_text_available()) { + this.clipboard.request_contents(Gdk.Atom.intern("text/plain", false), this.add_item); + } + } + + private void add_item(Gtk.Clipboard c, Gtk.SelectionData contents) { + var new_item = new ClipboardItem(contents); + + if (this.items.size == this.max_items) + this.items.remove_at(0); + + this.items.add(new_item); + + // update slices + this.delete_all(); + + for (int i=0; i { + this.items[int.parse(action.real_command)].paste(); + }); + this.add_action(action); + } + + } +} + +} diff --git a/src/actionGroups/devicesGroup.vala b/src/actionGroups/devicesGroup.vala new file mode 100644 index 0000000..3d2ced0 --- /dev/null +++ b/src/actionGroups/devicesGroup.vala @@ -0,0 +1,129 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////// +/// An ActionGroup which contains all currently plugged-in devices, +/// such as CD-ROM's or USB-sticks. +///////////////////////////////////////////////////////////////////// + +public class DevicesGroup : ActionGroup { + + ///////////////////////////////////////////////////////////////////// + /// Used to register this type of ActionGroup. It sets the display + /// name for this ActionGroup, it's icon name and the string used in + /// the pies.conf file for this kind of ActionGroups. + ///////////////////////////////////////////////////////////////////// + + public static void register(out string name, out string icon, out string settings_name) { + name = _("Devices"); + icon = "harddrive"; + settings_name = "devices"; + } + + ///////////////////////////////////////////////////////////////////// + /// Two members needed to avoid useless, frequent changes of the + /// stored Actions. + ///////////////////////////////////////////////////////////////////// + + private bool changing = false; + private bool changed_again = false; + + ///////////////////////////////////////////////////////////////////// + /// The VolumeMonitor used to check for added or removed devices. + ///////////////////////////////////////////////////////////////////// + + private GLib.VolumeMonitor monitor; + + ///////////////////////////////////////////////////////////////////// + /// C'tor, initializes all members. + ///////////////////////////////////////////////////////////////////// + + public DevicesGroup(string parent_id) { + GLib.Object(parent_id : parent_id); + } + + ///////////////////////////////////////////////////////////////////// + /// Construct block loads all currently plugged-in devices and + /// connects signal handlers to the VolumeMonitor. + ///////////////////////////////////////////////////////////////////// + + construct { + this.monitor = GLib.VolumeMonitor.get(); + + this.load(); + + // add monitor + this.monitor.mount_added.connect(this.reload); + this.monitor.mount_removed.connect(this.reload); + } + + ///////////////////////////////////////////////////////////////////// + /// Loads all currently plugged-in devices. + ///////////////////////////////////////////////////////////////////// + + private void load() { + // add root device + this.add_action(new UriAction(_("Root"), "harddrive", "file:///")); + + // add all other devices + foreach(var mount in this.monitor.get_mounts()) { + // get icon + var icon_names = mount.get_icon().to_string().split(" "); + + string icon = ""; + foreach (var icon_name in icon_names) { + if (Gtk.IconTheme.get_default().has_icon(icon_name)) { + icon = icon_name; + break; + } + } + + this.add_action(new UriAction(mount.get_name(), icon, mount.get_root().get_uri())); + } + } + + ///////////////////////////////////////////////////////////////////// + /// Reloads all devices. Is called when the VolumeMonitor changes. + ///////////////////////////////////////////////////////////////////// + + private void reload() { + // avoid too frequent changes... + if (!this.changing) { + this.changing = true; + Timeout.add(200, () => { + if (this.changed_again) { + this.changed_again = false; + return true; + } + + // reload + message("Devices changed..."); + this.delete_all(); + this.load(); + + this.changing = false; + return false; + }); + } else { + this.changed_again = true; + } + } +} + +} diff --git a/src/actionGroups/groupRegistry.vala b/src/actionGroups/groupRegistry.vala new file mode 100644 index 0000000..94169d5 --- /dev/null +++ b/src/actionGroups/groupRegistry.vala @@ -0,0 +1,89 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A which has knowledge on all possible acion group types. +///////////////////////////////////////////////////////////////////////// + +public class GroupRegistry : GLib.Object { + + ///////////////////////////////////////////////////////////////////// + /// A list containing all available ActionGroup types. + ///////////////////////////////////////////////////////////////////// + + public static Gee.ArrayList types { get; private set; } + + ///////////////////////////////////////////////////////////////////// + /// Three maps associating a displayable name for each ActionGroup, + /// an icon name and a name for the pies.conf file with it's type. + ///////////////////////////////////////////////////////////////////// + + public static Gee.HashMap names { get; private set; } + public static Gee.HashMap icons { get; private set; } + public static Gee.HashMap settings_names { get; private set; } + + + ///////////////////////////////////////////////////////////////////// + /// Registers all ActionGroup types. + ///////////////////////////////////////////////////////////////////// + + public static void init() { + types = new Gee.ArrayList(); + + names = new Gee.HashMap(); + icons = new Gee.HashMap(); + settings_names = new Gee.HashMap(); + + string name = ""; + string icon = ""; + string settings_name = ""; + + BookmarkGroup.register(out name, out icon, out settings_name); + types.add(typeof(BookmarkGroup)); + names.set(typeof(BookmarkGroup), name); + icons.set(typeof(BookmarkGroup), icon); + settings_names.set(typeof(BookmarkGroup), settings_name); + + DevicesGroup.register(out name, out icon, out settings_name); + types.add(typeof(DevicesGroup)); + names.set(typeof(DevicesGroup), name); + icons.set(typeof(DevicesGroup), icon); + settings_names.set(typeof(DevicesGroup), settings_name); + + MenuGroup.register(out name, out icon, out settings_name); + types.add(typeof(MenuGroup)); + names.set(typeof(MenuGroup), name); + icons.set(typeof(MenuGroup), icon); + settings_names.set(typeof(MenuGroup), settings_name); + + SessionGroup.register(out name, out icon, out settings_name); + types.add(typeof(SessionGroup)); + names.set(typeof(SessionGroup), name); + icons.set(typeof(SessionGroup), icon); + settings_names.set(typeof(SessionGroup), settings_name); + +// ClipboardGroup.register(out name, out icon, out settings_name); +// types.add(typeof(ClipboardGroup)); +// names.set(typeof(ClipboardGroup), name); +// icons.set(typeof(ClipboardGroup), icon); +// settings_names.set(typeof(ClipboardGroup), settings_name); + } +} + +} diff --git a/src/actionGroups/menuGroup.vala b/src/actionGroups/menuGroup.vala new file mode 100644 index 0000000..07a4bd1 --- /dev/null +++ b/src/actionGroups/menuGroup.vala @@ -0,0 +1,254 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// An ActionGroup which displays the user's main menu. It's a bit ugly, +/// but it supports both, an older version and libgnome-menus-3 at the +/// same time. +///////////////////////////////////////////////////////////////////////// + +public class MenuGroup : ActionGroup { + ///////////////////////////////////////////////////////////////////// + /// Used to register this type of ActionGroup. It sets the display + /// name for this ActionGroup, it's icon name and the string used in + /// the pies.conf file for this kind of ActionGroups. + ///////////////////////////////////////////////////////////////////// + + public static void register(out string name, out string icon, out string settings_name) { + name = _("Main menu"); + icon = "gnome-main-menu"; + settings_name = "menu"; + } + + ///////////////////////////////////////////////////////////////////// + /// True, if this MenuGroup is the top most menu. + ///////////////////////////////////////////////////////////////////// + + public bool is_toplevel {get; construct set; default = true;} + + ///////////////////////////////////////////////////////////////////// + /// The menu tree displayed by the MenuGroup. Only set for the + /// toplevel MenuGroup. + ///////////////////////////////////////////////////////////////////// + + private GMenu.Tree menu = null; + + ///////////////////////////////////////////////////////////////////// + /// A list of all sub menus of this MenuGroup. + ///////////////////////////////////////////////////////////////////// + + private Gee.ArrayList childs; + + ///////////////////////////////////////////////////////////////////// + /// Two members needed to avoid useless, frequent changes of the + /// stored Actions. + ///////////////////////////////////////////////////////////////////// + + private bool changing = false; + private bool changed_again = false; + + ///////////////////////////////////////////////////////////////////// + /// C'tor, initializes all members. Used for the toplevel menu. + ///////////////////////////////////////////////////////////////////// + + public MenuGroup(string parent_id) { + GLib.Object(parent_id : parent_id, is_toplevel : true); + } + + ///////////////////////////////////////////////////////////////////// + /// C'tor, initializes all members. Used for sub menus. + ///////////////////////////////////////////////////////////////////// + + public MenuGroup.sub_menu(string parent_id) { + GLib.Object(parent_id : parent_id, is_toplevel : false); + } + + construct { + this.childs = new Gee.ArrayList(); + + if (this.is_toplevel) { + #if HAVE_GMENU_3 + this.menu = new GMenu.Tree("applications.menu", GMenu.TreeFlags.INCLUDE_EXCLUDED); + this.menu.changed.connect(this.reload); + #endif + + this.load_toplevel(); + } + } + + ///////////////////////////////////////////////////////////////////// + /// Starts to load the menu. + ///////////////////////////////////////////////////////////////////// + + private void load_toplevel() { + #if HAVE_GMENU_3 + try { + if (this.menu.load_sync()) { + this.load_contents(this.menu.get_root_directory(), this.parent_id); + } + } catch (GLib.Error e) { + warning(e.message); + } + #else + this.menu = GMenu.Tree.lookup ("applications.menu", GMenu.TreeFlags.INCLUDE_EXCLUDED); + this.menu.add_monitor(this.reload); + var dir = this.menu.get_root_directory(); + this.load_contents(dir, this.parent_id); + #endif + } + + ///////////////////////////////////////////////////////////////////// + /// Parses the main menu recursively. + ///////////////////////////////////////////////////////////////////// + + private void load_contents(GMenu.TreeDirectory dir, string parent_id) { + #if HAVE_GMENU_3 + var item = dir.iter(); + + while (true) { + var type = item.next(); + if (type == GMenu.TreeItemType.INVALID) + break; + + if (type == GMenu.TreeItemType.DIRECTORY && !item.get_directory().get_is_nodisplay()) { + // create a MenuGroup for sub menus + string[] icons = item.get_directory().get_icon().to_string().split(" "); + string final_icon = "application-default-icon"; + + // search for available icons + foreach (var icon in icons) { + if (Gtk.IconTheme.get_default().has_icon(icon)) { + final_icon = icon; + break; + } + } + + var sub_menu = PieManager.create_dynamic_pie(item.get_directory().get_name(), final_icon); + var group = new MenuGroup.sub_menu(sub_menu.id); + group.add_action(new PieAction(parent_id, true)); + group.load_contents(item.get_directory(), sub_menu.id); + childs.add(group); + + sub_menu.add_group(group); + + this.add_action(new PieAction(sub_menu.id)); + + } else if (type == GMenu.TreeItemType.ENTRY ) { + // create an AppAction for entries + if (!item.get_entry().get_is_excluded()) { + this.add_action(ActionRegistry.new_for_app_info(item.get_entry().get_app_info())); + } + } + } + #else + foreach (var item in dir.get_contents()) { + switch(item.get_type()) { + case GMenu.TreeItemType.DIRECTORY: + // create a MenuGroup for sub menus + if (!((GMenu.TreeDirectory)item).get_is_nodisplay()) { + var sub_menu = PieManager.create_dynamic_pie( + ((GMenu.TreeDirectory)item).get_name(), + ((GMenu.TreeDirectory)item).get_icon()); + var group = new MenuGroup.sub_menu(sub_menu.id); + group.add_action(new PieAction(parent_id, true)); + group.load_contents((GMenu.TreeDirectory)item, sub_menu.id); + childs.add(group); + + sub_menu.add_group(group); + + this.add_action(new PieAction(sub_menu.id)); + } + break; + + case GMenu.TreeItemType.ENTRY: + // create an AppAction for entries + if (!((GMenu.TreeEntry)item).get_is_nodisplay() && !((GMenu.TreeEntry)item).get_is_excluded()) { + this.add_action(new AppAction(((GMenu.TreeEntry)item).get_name(), + ((GMenu.TreeEntry)item).get_icon(), + ((GMenu.TreeEntry)item).get_exec())); + } + break; + } + } + #endif + } + + ///////////////////////////////////////////////////////////////////// + /// Reloads the menu. + ///////////////////////////////////////////////////////////////////// + + private void reload() { + // avoid too frequent changes... + if (!this.changing) { + this.changing = true; + Timeout.add(500, () => { + if (this.changed_again) { + this.changed_again = false; + return true; + } + + // reload + message("Main menu changed..."); + #if !HAVE_GMENU_3 + this.menu.remove_monitor(this.reload); + #endif + + this.clear(); + this.load_toplevel(); + + this.changing = false; + return false; + }); + } else { + this.changed_again = true; + } + } + + ///////////////////////////////////////////////////////////////////// + /// Deletes all generated Pies, when the toplevel menu is deleted. + ///////////////////////////////////////////////////////////////////// + + public override void on_remove() { + if (this.is_toplevel) + this.clear(); + } + + ///////////////////////////////////////////////////////////////////// + /// Clears this ActionGroup recursively. + ///////////////////////////////////////////////////////////////////// + + private void clear() { + foreach (var child in childs) + child.clear(); + + if (!this.is_toplevel) + PieManager.remove_pie(this.parent_id); + + this.delete_all(); + + this.childs.clear(); + + #if !HAVE_GMENU_3 + this.menu = null; + #endif + + } +} + +} diff --git a/src/actionGroups/sessionGroup.vala b/src/actionGroups/sessionGroup.vala new file mode 100644 index 0000000..9fcab1d --- /dev/null +++ b/src/actionGroups/sessionGroup.vala @@ -0,0 +1,68 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////// +/// An ActionGroup which has three Actions: Logout, Shutdown and +/// Reboot. +///////////////////////////////////////////////////////////////////// + +public class SessionGroup : ActionGroup { + + ///////////////////////////////////////////////////////////////////// + /// Used to register this type of ActionGroup. It sets the display + /// name for this ActionGroup, it's icon name and the string used in + /// the pies.conf file for this kind of ActionGroups. + ///////////////////////////////////////////////////////////////////// + + public static void register(out string name, out string icon, out string settings_name) { + name = _("Session Control"); + icon = "gnome-logout"; + settings_name = "session"; + } + + ///////////////////////////////////////////////////////////////////// + /// C'tor, initializes all members. + ///////////////////////////////////////////////////////////////////// + + public SessionGroup(string parent_id) { + GLib.Object(parent_id : parent_id); + } + + ///////////////////////////////////////////////////////////////////// + /// Construct block adds the three Actions. + ///////////////////////////////////////////////////////////////////// + + construct { + this.add_action(new AppAction(_("Shutdown"), "gnome-shutdown", + "dbus-send --print-reply --dest=org.gnome.SessionManager /org/gnome/SessionManager org.gnome.SessionManager.RequestShutdown")); + + this.add_action(new AppAction(_("Logout"), "gnome-session-logout", + "dbus-send --print-reply --dest=org.gnome.SessionManager /org/gnome/SessionManager org.gnome.SessionManager.Logout uint32:1")); + + this.add_action(new AppAction(_("Reboot"), "gnome-session-reboot", + "dbus-send --print-reply --dest=org.gnome.SessionManager /org/gnome/SessionManager org.gnome.SessionManager.RequestReboot")); + } + + // TODO: check for available interfaces --- these may work too: + // dbus-send --print-reply --system --dest=org.freedesktop.Hal /org/freedesktop/Hal/devices/computer org.freedesktop.Hal.Device.SystemPowerManagement.Shutdown + // dbus-send --print-reply --dest=org.kde.ksmserver /KSMServer org.kde.KSMServerInterface.logout 0 2 2 + // dbus-send --system --print-reply --dest="org.freedesktop.ConsoleKit" /org/freedesktop/ConsoleKit/Manager org.freedesktop.ConsoleKit.Manager.Stop +} + +} diff --git a/src/actions/action.vala b/src/actions/action.vala new file mode 100644 index 0000000..ceed357 --- /dev/null +++ b/src/actions/action.vala @@ -0,0 +1,77 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A base class for actions, which are executed when the user +/// activates a pie's slice. +///////////////////////////////////////////////////////////////////////// + +public abstract class Action : GLib.Object { + + ///////////////////////////////////////////////////////////////////// + /// The command which gets executed when user activates the Slice. + /// It may be anything but has to be representable with a string. + ///////////////////////////////////////////////////////////////////// + + public abstract string real_command { get; construct set; } + + ///////////////////////////////////////////////////////////////////// + /// The command displayed to the user. It should be a bit more + /// beautiful than the real_command. + ///////////////////////////////////////////////////////////////////// + + public abstract string display_command { get; } + + ///////////////////////////////////////////////////////////////////// + /// The name of the Action. + ///////////////////////////////////////////////////////////////////// + + public virtual string name { get; protected set; } + + ///////////////////////////////////////////////////////////////////// + /// The name of the icon of this Action. It should be in the users + /// current icon theme. + ///////////////////////////////////////////////////////////////////// + + public virtual string icon { get; protected set; } + + ///////////////////////////////////////////////////////////////////// + /// True, if this Action is the quickAction of the associated Pie. + /// The quickAction of a Pie gets executed when the users clicks on + /// the center of a Pie. + ///////////////////////////////////////////////////////////////////// + + public virtual bool is_quick_action { get; protected set; } + + ///////////////////////////////////////////////////////////////////// + /// C'tor, initializes all members. + ///////////////////////////////////////////////////////////////////// + + public Action(string name, string icon, bool is_quick_action) { + GLib.Object(name : name, icon : icon, is_quick_action : is_quick_action); + } + + ///////////////////////////////////////////////////////////////////// + /// This one is called, when the user activates the Slice. + ///////////////////////////////////////////////////////////////////// + + public abstract void activate(); +} + +} diff --git a/src/actions/actionRegistry.vala b/src/actions/actionRegistry.vala new file mode 100644 index 0000000..091865f --- /dev/null +++ b/src/actions/actionRegistry.vala @@ -0,0 +1,200 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A which has knowledge on all possible acion types. +///////////////////////////////////////////////////////////////////////// + +public class ActionRegistry : GLib.Object { + + ///////////////////////////////////////////////////////////////////// + /// A list containing all available Action types. + ///////////////////////////////////////////////////////////////////// + + public static Gee.ArrayList types { get; private set; } + + ///////////////////////////////////////////////////////////////////// + /// Three maps associating a displayable name for each Action, + /// whether it has a custom icon and a name for the pies.conf + /// file with it's type. + ///////////////////////////////////////////////////////////////////// + + public static Gee.HashMap names { get; private set; } + public static Gee.HashMap icon_name_editables { get; private set; } + public static Gee.HashMap settings_names { get; private set; } + + ///////////////////////////////////////////////////////////////////// + /// Registers all Action types. + ///////////////////////////////////////////////////////////////////// + + public static void init() { + types = new Gee.ArrayList(); + + names = new Gee.HashMap(); + icon_name_editables = new Gee.HashMap(); + settings_names = new Gee.HashMap(); + + string name = ""; + bool icon_name_editable = true; + string settings_name = ""; + + AppAction.register(out name, out icon_name_editable, out settings_name); + types.add(typeof(AppAction)); + names.set(typeof(AppAction), name); + icon_name_editables.set(typeof(AppAction), icon_name_editable); + settings_names.set(typeof(AppAction), settings_name); + + KeyAction.register(out name, out icon_name_editable, out settings_name); + types.add(typeof(KeyAction)); + names.set(typeof(KeyAction), name); + icon_name_editables.set(typeof(KeyAction), icon_name_editable); + settings_names.set(typeof(KeyAction), settings_name); + + PieAction.register(out name, out icon_name_editable, out settings_name); + types.add(typeof(PieAction)); + names.set(typeof(PieAction), name); + icon_name_editables.set(typeof(PieAction), icon_name_editable); + settings_names.set(typeof(PieAction), settings_name); + + UriAction.register(out name, out icon_name_editable, out settings_name); + types.add(typeof(UriAction)); + names.set(typeof(UriAction), name); + icon_name_editables.set(typeof(UriAction), icon_name_editable); + settings_names.set(typeof(UriAction), settings_name); + } + + ///////////////////////////////////////////////////////////////////// + /// A helper method which creates an Action, appropriate for the + /// given URI. This can result in an UriAction or in an AppAction, + /// depending on the Type of the URI. + ///////////////////////////////////////////////////////////////////// + + public static Action? new_for_uri(string uri, string? name = null) { + var file = GLib.File.new_for_uri(uri); + var scheme = file.get_uri_scheme(); + + string final_icon = ""; + string final_name = file.get_basename(); + + switch (scheme) { + case "application": + var file_name = uri.split("//")[1]; + + var desktop_file = GLib.File.new_for_path("/usr/share/applications/" + file_name); + if (desktop_file.query_exists()) + return new_for_desktop_file(desktop_file.get_path()); + + break; + + case "trash": + final_icon = "user-trash"; + final_name = _("Trash"); + break; + + case "http": case "https": + final_icon = "www"; + break; + + case "ftp": case "sftp": + final_icon = "folder-remote"; + break; + + default: + try { + var info = file.query_info("*", GLib.FileQueryInfoFlags.NONE); + + if (info.get_content_type() == "application/x-desktop") + return new_for_desktop_file(file.get_parse_name()); + + // search for an appropriate icon + var gicon = info.get_icon(); + string[] icons = gicon.to_string().split(" "); + + foreach (var icon in icons) { + if (Gtk.IconTheme.get_default().has_icon(icon)) { + final_icon = icon; + break; + } + } + + } catch (GLib.Error e) { + warning(e.message); + } + + break; + } + + if (!Gtk.IconTheme.get_default().has_icon(final_icon)) + final_icon = "application-default-icon"; + + if (name != null) + final_name = name; + + return new UriAction(final_name, final_icon, uri); + } + + ///////////////////////////////////////////////////////////////////// + /// A helper method which creates an AppAction for given AppInfo. + ///////////////////////////////////////////////////////////////////// + + public static Action? new_for_app_info(GLib.AppInfo info) { + string[] icons = info.get_icon().to_string().split(" "); + string final_icon = "application-default-icon"; + + // search for available icons + foreach (var icon in icons) { + if (Gtk.IconTheme.get_default().has_icon(icon)) { + final_icon = icon; + break; + } + } + + return new AppAction(info.get_display_name() , final_icon, info.get_commandline()); + } + + ///////////////////////////////////////////////////////////////////// + /// A helper method which creates an AppAction for given *.desktop + /// file. + ///////////////////////////////////////////////////////////////////// + + public static Action? new_for_desktop_file(string file_name) { + var info = new DesktopAppInfo.from_filename(file_name); + return new_for_app_info(info); + } + + ///////////////////////////////////////////////////////////////////// + /// A helper method which creates an AppAction for given mime type. + ///////////////////////////////////////////////////////////////////// + + public static Action? default_for_mime_type(string type) { + var info = AppInfo.get_default_for_type(type, false); + return new_for_app_info(info); + } + + ///////////////////////////////////////////////////////////////////// + /// A helper method which creates an AppAction for given uri scheme. + ///////////////////////////////////////////////////////////////////// + + public static Action? default_for_uri(string uri) { + var info = AppInfo. get_default_for_uri_scheme(uri); + return new_for_app_info(info); + } +} + +} diff --git a/src/actions/appAction.vala b/src/actions/appAction.vala new file mode 100644 index 0000000..d8363e4 --- /dev/null +++ b/src/actions/appAction.vala @@ -0,0 +1,72 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// This type of Action launches an application or a custom command. +///////////////////////////////////////////////////////////////////////// + +public class AppAction : Action { + + ///////////////////////////////////////////////////////////////////// + /// Used to register this type of Action. It sets the display name + /// for this Action, whether it has a custom Icon/Name and the string + /// used in the pies.conf file for this kind of Actions. + ///////////////////////////////////////////////////////////////////// + + public static void register(out string name, out bool icon_name_editable, out string settings_name) { + name = _("Launch application"); + icon_name_editable = true; + settings_name = "app"; + } + + ///////////////////////////////////////////////////////////////////// + /// Stores the command line. + ///////////////////////////////////////////////////////////////////// + + public override string real_command { get; construct set; } + + ///////////////////////////////////////////////////////////////////// + /// Simply returns the real_command. No beautification. + ///////////////////////////////////////////////////////////////////// + + public override string display_command { get {return real_command;} } + + ///////////////////////////////////////////////////////////////////// + /// C'tor, initializes all members. + ///////////////////////////////////////////////////////////////////// + + public AppAction(string name, string icon, string command, bool is_quick_action = false) { + GLib.Object(name : name, icon : icon, real_command : command, is_quick_action : is_quick_action); + } + + ///////////////////////////////////////////////////////////////////// + /// Launches the desired command. + ///////////////////////////////////////////////////////////////////// + + public override void activate() { + try{ + var item = GLib.AppInfo.create_from_commandline(this.real_command, null, GLib.AppInfoCreateFlags.NONE); + item.launch(null, null); + } catch (Error e) { + warning(e.message); + } + } +} + +} diff --git a/src/actions/keyAction.vala b/src/actions/keyAction.vala new file mode 100644 index 0000000..0f6d094 --- /dev/null +++ b/src/actions/keyAction.vala @@ -0,0 +1,77 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// This type of Action "presses" a key stroke. +///////////////////////////////////////////////////////////////////////// + +public class KeyAction : Action { + + ///////////////////////////////////////////////////////////////////// + /// Used to register this type of Action. It sets the display name + /// for this Action, whether it has a custom Icon/Name and the string + /// used in the pies.conf file for this kind of Actions. + ///////////////////////////////////////////////////////////////////// + + public static void register(out string name, out bool icon_name_editable, out string settings_name) { + name = _("Press key stroke"); + icon_name_editable = true; + settings_name = "key"; + } + + ///////////////////////////////////////////////////////////////////// + /// Stores the accelerator of this action. + ///////////////////////////////////////////////////////////////////// + + public override string real_command { get; construct set; } + + ///////////////////////////////////////////////////////////////////// + /// Returns a human readable form of the accelerator. + ///////////////////////////////////////////////////////////////////// + + public override string display_command { get {return key.label;} } + + ///////////////////////////////////////////////////////////////////// + /// The simulated key which gets 'pressed' on execution. + ///////////////////////////////////////////////////////////////////// + + public Key key { get; set; } + + ///////////////////////////////////////////////////////////////////// + /// C'tor, initializes all members. + ///////////////////////////////////////////////////////////////////// + + public KeyAction(string name, string icon, string command, bool is_quick_action = false) { + GLib.Object(name : name, icon : icon, real_command : command, is_quick_action : is_quick_action); + } + + construct { + this.key = new Key(real_command); + } + + ///////////////////////////////////////////////////////////////////// + /// Presses the desired key. + ///////////////////////////////////////////////////////////////////// + + public override void activate() { + key.press(); + } +} + +} diff --git a/src/actions/pieAction.vala b/src/actions/pieAction.vala new file mode 100644 index 0000000..53ea919 --- /dev/null +++ b/src/actions/pieAction.vala @@ -0,0 +1,95 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// This Action opens another pie. +///////////////////////////////////////////////////////////////////////// + +public class PieAction : Action { + + ///////////////////////////////////////////////////////////////////// + /// Used to register this type of Action. It sets the display name + /// for this Action, whether it has a custom Icon/Name and the string + /// used in the pies.conf file for this kind of Actions. + ///////////////////////////////////////////////////////////////////// + + public static void register(out string name, out bool icon_name_editable, out string settings_name) { + name = _("Open Pie"); + icon_name_editable = false; + settings_name = "pie"; + } + + ///////////////////////////////////////////////////////////////////// + /// Stores the ID of the referenced Pie. + ///////////////////////////////////////////////////////////////////// + + public override string real_command { get; construct set; } + + ///////////////////////////////////////////////////////////////////// + /// Returns the name of the referenced Pie. + ///////////////////////////////////////////////////////////////////// + + public override string display_command { get {return name;} } + + ///////////////////////////////////////////////////////////////////// + /// Returns the name of the referenced Pie. + ///////////////////////////////////////////////////////////////////// + + public override string name { + get { + var referee = PieManager.all_pies[real_command]; + if (referee != null) + return referee.name; + return ""; + } + protected set {} + } + + ///////////////////////////////////////////////////////////////////// + /// Returns the icon of the referenced Pie. + ///////////////////////////////////////////////////////////////////// + + public override string icon { + get { + var referee = PieManager.all_pies[real_command]; + if (referee != null) + return referee.icon; + return ""; + } + protected set {} + } + + ///////////////////////////////////////////////////////////////////// + /// C'tor, initializes all members. + ///////////////////////////////////////////////////////////////////// + + public PieAction(string id, bool is_quick_action = false) { + GLib.Object(name : "", icon : "", real_command : id, is_quick_action : is_quick_action); + } + + ///////////////////////////////////////////////////////////////////// + /// Opens the desired Pie. + ///////////////////////////////////////////////////////////////////// + + public override void activate() { + PieManager.open_pie(real_command); + } +} + +} diff --git a/src/actions/sigAction.vala b/src/actions/sigAction.vala new file mode 100644 index 0000000..cec9836 --- /dev/null +++ b/src/actions/sigAction.vala @@ -0,0 +1,63 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// This type of Action can't be selected by the user, therefore there is +/// no register() method for this class. But it may be useful for +/// ActionGroups: It emits a signal on activation. +///////////////////////////////////////////////////////////////////////// + +public class SigAction : Action { + + ///////////////////////////////////////////////////////////////////// + /// This signal is emitted on activation. + ///////////////////////////////////////////////////////////////////// + + public signal void activated(); + + ///////////////////////////////////////////////////////////////////// + /// This may store something useful. + ///////////////////////////////////////////////////////////////////// + + public override string real_command { get; construct set; } + + ///////////////////////////////////////////////////////////////////// + /// Only for inheritance... Greetings to Liskov. + ///////////////////////////////////////////////////////////////////// + + public override string display_command { get {return real_command;} } + + ///////////////////////////////////////////////////////////////////// + /// C'tor, initializes all members. + ///////////////////////////////////////////////////////////////////// + + public SigAction(string name, string icon, string command, bool is_quick_action = false) { + GLib.Object(name : name, icon : icon, real_command : command, is_quick_action : is_quick_action); + } + + ///////////////////////////////////////////////////////////////////// + /// Emits the signal on activation. + ///////////////////////////////////////////////////////////////////// + + public override void activate() { + this.activated(); + } +} + +} diff --git a/src/actions/uriAction.vala b/src/actions/uriAction.vala new file mode 100644 index 0000000..25d5c75 --- /dev/null +++ b/src/actions/uriAction.vala @@ -0,0 +1,71 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// This type of Action opens the default application for an URI. +///////////////////////////////////////////////////////////////////////// + +public class UriAction : Action { + + ///////////////////////////////////////////////////////////////////// + /// Used to register this type of Action. It sets the display name + /// for this Action, whether it has a custom Icon/Name and the string + /// used in the pies.conf file for this kind of Actions. + ///////////////////////////////////////////////////////////////////// + + public static void register(out string name, out bool icon_name_editable, out string settings_name) { + name = _("Open URI"); + icon_name_editable = true; + settings_name = "uri"; + } + + ///////////////////////////////////////////////////////////////////// + /// The URI of this Action. + ///////////////////////////////////////////////////////////////////// + + public override string real_command { get; construct set; } + + ///////////////////////////////////////////////////////////////////// + /// Returns only the real URI. An URI can't be beautified. + ///////////////////////////////////////////////////////////////////// + + public override string display_command { get {return real_command;} } + + ///////////////////////////////////////////////////////////////////// + /// C'tor, initializes all members. + ///////////////////////////////////////////////////////////////////// + + public UriAction(string name, string icon, string command, bool is_quick_action = false) { + GLib.Object(name : name, icon : icon, real_command : command, is_quick_action : is_quick_action); + } + + ///////////////////////////////////////////////////////////////////// + /// Opens the default application for the URI. + ///////////////////////////////////////////////////////////////////// + + public override void activate() { + try{ + GLib.AppInfo.launch_default_for_uri(real_command, null); + } catch (Error e) { + warning(e.message); + } + } +} + +} diff --git a/src/deamon.vala b/src/deamon.vala new file mode 100644 index 0000000..af232eb --- /dev/null +++ b/src/deamon.vala @@ -0,0 +1,175 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +///////////////////////////////////////////////////////////////////// +/// TODO-List: +/// IconSelectWindow +/// PieList +/// PieWindow +/// CenterRenderer +/// SliceRenderer +/// PieRenderer +///////////////////////////////////////////////////////////////////// + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// This class runs in the background. It has an Indicator sitting in the +/// user's panel. It initializes everything and guarantees that there is +/// only one instance of Gnome-Pie running. +///////////////////////////////////////////////////////////////////////// + +public class Deamon : GLib.Object { + + ///////////////////////////////////////////////////////////////////// + /// The beginning of everything. + ///////////////////////////////////////////////////////////////////// + + public static int main(string[] args) { + Logger.init(); + Gtk.init(ref args); + Paths.init(); + + // create the Deamon and run it + var deamon = new GnomePie.Deamon(); + deamon.run(args); + + return 0; + } + + ///////////////////////////////////////////////////////////////////// + /// The AppIndicator of Gnome-Pie. + ///////////////////////////////////////////////////////////////////// + + private Indicator indicator = null; + + ///////////////////////////////////////////////////////////////////// + /// Varaibles set by the commend line parser. + ///////////////////////////////////////////////////////////////////// + + private static string open_pie = null; + private static bool reset = false; + + ///////////////////////////////////////////////////////////////////// + /// Available command line options. + ///////////////////////////////////////////////////////////////////// + + private const GLib.OptionEntry[] options = { + { "open", 'o', 0, GLib.OptionArg.STRING, out open_pie, + "Open the Pie with the given ID", "ID" }, + { "reset", 'r', 0, GLib.OptionArg.NONE, out reset, + "Reset all options to default values" }, + { null } + }; + + ///////////////////////////////////////////////////////////////////// + /// C'tor of the Deamon. It checks whether it's the firts running + /// instance of Gnome-Pie. + ///////////////////////////////////////////////////////////////////// + + public void run(string[] args) { + // create command line options + var context = new GLib.OptionContext(""); + context.set_help_enabled(true); + context.add_main_entries(options, null); + context.add_group(Gtk.get_option_group (false)); + + try { + context.parse(ref args); + } catch(GLib.OptionError error) { + warning(error.message); + } + + if (this.reset) { + if (GLib.FileUtils.remove(Paths.pie_config) == 0) + message("Removed file \"%s\"", Paths.pie_config); + if (GLib.FileUtils.remove(Paths.settings) == 0) + message("Removed file \"%s\"", Paths.settings); + return; + } + + // create unique application + var app = new Unique.App("org.gnome.gnomepie", null); + + if (app.is_running) { + // inform the running instance of the pie to be opened + if (open_pie != null) { + var data = new Unique.MessageData(); + data.set_text(open_pie, open_pie.length); + app.send_message(Unique.Command.ACTIVATE, data); + return; + } + + app.send_message(Unique.Command.ACTIVATE, null); + return; + } + + // wait for incoming messages + app.message_received.connect((cmd, data, event_time) => { + if (cmd == Unique.Command.ACTIVATE) { + var pie = data.get_text(); + + if (pie != "") PieManager.open_pie(pie); + else this.indicator.show_preferences(); + + return Unique.Response.OK; + } + + return Unique.Response.PASSTHROUGH; + }); + + // init toolkits and static stuff + Gdk.threads_init(); + ActionRegistry.init(); + GroupRegistry.init(); + PieManager.init(); + Icon.init(); + ThemedIcon.init(); + RenderedText.init(); + + // init locale support + Intl.bindtextdomain ("gnomepie", Paths.locales); + Intl.textdomain ("gnomepie"); + + // launch the indicator + this.indicator = new Indicator(); + + // connect SigHandlers + Posix.signal(Posix.SIGINT, sig_handler); + Posix.signal(Posix.SIGTERM, sig_handler); + + // finished loading... so run the prog! + message("Started happily..."); + + // open pie if neccessary + if (open_pie != null) PieManager.open_pie(open_pie); + + Gtk.main(); + } + + ///////////////////////////////////////////////////////////////////// + /// Print a nifty message when the prog is killed. + ///////////////////////////////////////////////////////////////////// + + private static void sig_handler(int sig) { + stdout.printf("\n"); + message("Caught signal (%d), bye!".printf(sig)); + Gtk.main_quit(); + } +} + +} diff --git a/src/gui/about.vala b/src/gui/about.vala new file mode 100644 index 0000000..1ace9cb --- /dev/null +++ b/src/gui/about.vala @@ -0,0 +1,43 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A simple about Dialog. +///////////////////////////////////////////////////////////////////////// + +public class GnomePieAboutDialog: Gtk.AboutDialog { + + public GnomePieAboutDialog () { + string[] devs = {"Simon Schneegans ", + "Francesco Piccinno"}; + string[] artists = {"Simon Schneegans "}; + GLib.Object ( + artists : artists, + authors : devs, + copyright : "Copyright (C) 2011 Simon Schneegans ", + program_name: "Gnome-Pie", + logo_icon_name: "gnome-pie", + website: "http://www.simonschneegans.de/?page_id=12", + website_label: "www.gnome-pie.simonschneegans.de", + version: "0.2" + ); + } +} + +} diff --git a/src/gui/cellRendererIcon.vala b/src/gui/cellRendererIcon.vala new file mode 100644 index 0000000..959a0b7 --- /dev/null +++ b/src/gui/cellRendererIcon.vala @@ -0,0 +1,132 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A cellrenderer which displays an Icon. When clicked onto, a window +/// opens for selecting another icon. This needs to be a subclass of +/// Gtk.CellRendererText because Gtk.CellRendererPixbuf can't receive +/// click events. Internally it stores a Gtk.CellRendererPixbuf +/// which renders and stuff. +///////////////////////////////////////////////////////////////////////// + +public class CellRendererIcon : Gtk.CellRendererText { + + ///////////////////////////////////////////////////////////////////// + /// This signal is emitted when the user selects another icon. + ///////////////////////////////////////////////////////////////////// + + public signal void on_select(string path, string icon); + + ///////////////////////////////////////////////////////////////////// + /// The IconSelectWindow which is shown on click. + ///////////////////////////////////////////////////////////////////// + + private IconSelectWindow select_window = null; + + ///////////////////////////////////////////////////////////////////// + /// The internal Renderer used for drawing. + ///////////////////////////////////////////////////////////////////// + + private Gtk.CellRendererPixbuf renderer = null; + + ///////////////////////////////////////////////////////////////////// + /// A helper variable, needed to emit the current path. + ///////////////////////////////////////////////////////////////////// + + private string current_path = ""; + + public string icon_name { get; set; } + + ///////////////////////////////////////////////////////////////////// + /// Forward some parts of the CellRendererPixbuf's interface. + ///////////////////////////////////////////////////////////////////// + + public bool follow_state { + get { return renderer.follow_state; } + set { renderer.follow_state = value; } + } + + public bool icon_sensitive { + get { return renderer.sensitive; } + set { renderer.sensitive = value; } + } + + public Gdk.Pixbuf pixbuf { + owned get { return renderer.pixbuf; } + set { renderer.pixbuf = value; } + } + + ///////////////////////////////////////////////////////////////////// + /// C'tor, creates a new CellRendererIcon. + ///////////////////////////////////////////////////////////////////// + + public CellRendererIcon() { + this.select_window = new IconSelectWindow(); + this.renderer = new Gtk.CellRendererPixbuf(); + + this.select_window.on_select.connect((icon) => { + this.on_select(current_path, icon); + }); + } + + ///////////////////////////////////////////////////////////////////// + /// Forward some parts of the CellRendererPixbuf's interface. + ///////////////////////////////////////////////////////////////////// + + public override void get_size (Gtk.Widget widget, Gdk.Rectangle? cell_area, + out int x_offset, out int y_offset, + out int width, out int height) { + + this.renderer.get_size(widget, cell_area, out x_offset, out y_offset, out width, out height); + } + + ///////////////////////////////////////////////////////////////////// + /// Forward some parts of the CellRendererPixbuf's interface. + ///////////////////////////////////////////////////////////////////// + + public override void render (Gdk.Window window, Gtk.Widget widget, + Gdk.Rectangle bg_area, + Gdk.Rectangle cell_area, + Gdk.Rectangle expose_area, + Gtk.CellRendererState flags) { + + this.renderer.render(window, widget, bg_area, cell_area, expose_area, flags); + } + + ///////////////////////////////////////////////////////////////////// + /// Open the IconSelectWindow on click. + ///////////////////////////////////////////////////////////////////// + + public override unowned Gtk.CellEditable start_editing( + Gdk.Event event, Gtk.Widget widget, string path, Gdk.Rectangle bg_area, + Gdk.Rectangle cell_area, Gtk.CellRendererState flags) { + + this.select_window.set_transient_for((Gtk.Window)widget.get_toplevel()); + this.select_window.set_modal(true); + + this.current_path = path; + this.select_window.show(); + this.select_window.active_icon = this.icon_name; + + return this.renderer.start_editing(event, widget, path, bg_area, cell_area, flags); + } +} + +} + diff --git a/src/gui/iconSelectWindow.vala b/src/gui/iconSelectWindow.vala new file mode 100644 index 0000000..2274ec5 --- /dev/null +++ b/src/gui/iconSelectWindow.vala @@ -0,0 +1,349 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A window which allows selection of an Icon of the user's current icon +/// theme. Loading of Icons happens in an extra thread and a spinner is +/// displayed while loading. +///////////////////////////////////////////////////////////////////////// + +public class IconSelectWindow : Gtk.Dialog { + + private static Gtk.ListStore icon_list = null; + + private static bool loading {get; set; default = false;} + private static bool need_reload {get; set; default = true;} + + private const string disabled_contexts = "Animations, FileSystems, MimeTypes"; + private Gtk.TreeModelFilter icon_list_filtered = null; + private Gtk.IconView icon_view = null; + private Gtk.Spinner spinner = null; + + private Gtk.FileChooserWidget file_chooser = null; + + private Gtk.Notebook tabs = null; + + private class ListEntry { + public string name; + public IconContext context; + public Gdk.Pixbuf pixbuf; + } + + private GLib.AsyncQueue load_queue; + + private enum IconContext { + ALL, + APPS, + ACTIONS, + PLACES, + FILES, + EMOTES, + OTHER + } + + public string _active_icon = "application-default-icon"; + + public string active_icon { + get { + return _active_icon; + } + set { + if (value.contains("/")) { + this.file_chooser.set_filename(value); + this.tabs.set_current_page(1); + } else { + this.icon_list_filtered.foreach((model, path, iter) => { + string name = ""; + model.get(iter, 0, out name); + + if (name == value) { + this.icon_view.select_path(path); + this.icon_view.scroll_to_path(path, true, 0.5f, 0.0f); + this.icon_view.set_cursor(path, null, false); + } + return (name == value); + }); + + this.tabs.set_current_page(0); + } + } + } + + public signal void on_select(string icon_name); + + public IconSelectWindow() { + this.title = _("Choose an Icon"); + this.set_size_request(520, 520); + this.delete_event.connect(hide_on_delete); + this.load_queue = new GLib.AsyncQueue(); + + if (this.icon_list == null) { + this.icon_list = new Gtk.ListStore(3, typeof(string), typeof(IconContext), typeof(Gdk.Pixbuf)); + this.icon_list.set_default_sort_func(() => {return 0;}); + + Gtk.IconTheme.get_default().changed.connect(() => { + if (this.visible) load_icons(); + else need_reload = true; + }); + } + + this.icon_list_filtered = new Gtk.TreeModelFilter(this.icon_list, null); + + var container = new Gtk.VBox(false, 12); + container.set_border_width(12); + + // tab container + this.tabs = new Gtk.Notebook(); + + var theme_tab = new Gtk.VBox(false, 12); + theme_tab.set_border_width(12); + + var context_combo = new Gtk.ComboBox.text(); + context_combo.append_text(_("All icons")); + context_combo.append_text(_("Applications")); + context_combo.append_text(_("Actions")); + context_combo.append_text(_("Places")); + context_combo.append_text(_("File types")); + context_combo.append_text(_("Emotes")); + context_combo.append_text(_("Miscellaneous")); + + context_combo.set_active(0); + + context_combo.changed.connect(() => { + this.icon_list_filtered.refilter(); + }); + + theme_tab.pack_start(context_combo, false, false); + + var filter = new Gtk.Entry(); + filter.primary_icon_stock = Gtk.Stock.FIND; + filter.primary_icon_activatable = false; + filter.secondary_icon_stock = Gtk.Stock.CLEAR; + theme_tab.pack_start(filter, false, false); + + this.icon_list_filtered.set_visible_func((model, iter) => { + string name = ""; + IconContext context = IconContext.ALL; + model.get(iter, 0, out name); + model.get(iter, 1, out context); + + if (name == null) return false; + + return (context_combo.get_active() == context || + context_combo.get_active() == IconContext.ALL) && + name.down().contains(filter.text.down()); + }); + + filter.icon_release.connect((pos, event) => { + if (pos == Gtk.EntryIconPosition.SECONDARY) + filter.text = ""; + }); + + filter.notify["text"].connect(() => { + this.icon_list_filtered.refilter(); + }); + + var scroll = new Gtk.ScrolledWindow (null, null); + scroll.set_policy (Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + scroll.set_shadow_type (Gtk.ShadowType.IN); + + this.icon_view = new Gtk.IconView.with_model(this.icon_list_filtered); + this.icon_view.item_width = 32; + this.icon_view.item_padding = 3; + this.icon_view.pixbuf_column = 2; + this.icon_view.tooltip_column = 0; + + this.icon_view.selection_changed.connect(() => { + foreach (var path in this.icon_view.get_selected_items()) { + Gtk.TreeIter iter; + this.icon_list_filtered.get_iter(out iter, path); + icon_list_filtered.get(iter, 0, out this._active_icon); + } + }); + + this.icon_view.item_activated.connect((path) => { + Gtk.TreeIter iter; + this.icon_list_filtered.get_iter(out iter, path); + this.icon_list_filtered.get(iter, 0, out this._active_icon); + this.on_select(this._active_icon); + this.hide(); + }); + + scroll.add(this.icon_view); + + theme_tab.pack_start(scroll, true, true); + + tabs.append_page(theme_tab, new Gtk.Label(_("Icon Theme"))); + + var custom_tab = new Gtk.VBox(false, 6); + custom_tab.border_width = 12; + + this.file_chooser = new Gtk.FileChooserWidget(Gtk.FileChooserAction.OPEN); + var file_filter = new Gtk.FileFilter(); + file_filter.add_pixbuf_formats(); + file_filter.set_name(_("All supported image formats")); + file_chooser.add_filter(file_filter); + + file_chooser.selection_changed.connect(() => { + if (file_chooser.get_filename() != null && GLib.FileUtils.test(file_chooser.get_filename(), GLib.FileTest.IS_REGULAR)) + this._active_icon = file_chooser.get_filename(); + }); + + file_chooser.file_activated.connect(() => { + this._active_icon = file_chooser.get_filename(); + this.on_select(this._active_icon); + this.hide(); + }); + + + custom_tab.pack_start(file_chooser, true, true); + + tabs.append_page(custom_tab, new Gtk.Label(_("Custom Icon"))); + + container.pack_start(tabs, true, true); + + // button box + var bottom_box = new Gtk.HBox(false, 0); + + var bbox = new Gtk.HButtonBox(); + bbox.set_spacing(6); + bbox.set_layout(Gtk.ButtonBoxStyle.END); + + var cancel_button = new Gtk.Button.from_stock(Gtk.Stock.CANCEL); + cancel_button.clicked.connect(() => { + this.hide(); + }); + bbox.pack_start(cancel_button); + + var ok_button = new Gtk.Button.from_stock(Gtk.Stock.OK); + ok_button.clicked.connect(() => { + this.on_select(this._active_icon); + this.hide(); + }); + bbox.pack_start(ok_button); + + bottom_box.pack_end(bbox, false); + + this.spinner = new Gtk.Spinner(); + this.spinner.set_size_request(16, 16); + this.spinner.start(); + + bottom_box.pack_start(this.spinner, false, false); + + container.pack_start(bottom_box, false, false); + + this.vbox.pack_start(container, true, true); + + this.vbox.show_all(); + + this.set_focus(this.icon_view); + } + + public override void show() { + base.show(); + this.action_area.hide(); + + if (this.need_reload) { + this.need_reload = false; + this.load_icons(); + } + } + + private void load_icons() { + if (!this.loading) { + this.loading = true; + this.icon_list.clear(); + + if (spinner != null) + this.spinner.visible = true; + + this.icon_list.set_sort_column_id(-1, Gtk.SortType.ASCENDING); + + try { + unowned Thread loader = Thread.create(load_thread, false); + loader.set_priority(ThreadPriority.LOW); + } catch (GLib.ThreadError e) { + error("Failed to create icon loader thread!"); + } + + Timeout.add(200, () => { + while (this.load_queue.length() > 0) { + var new_entry = this.load_queue.pop(); + Gtk.TreeIter current; + this.icon_list.append(out current); + this.icon_list.set(current, 0, new_entry.name, + 1, new_entry.context, + 2, new_entry.pixbuf); + } + + if (!this.loading) this.icon_list.set_sort_column_id(0, Gtk.SortType.ASCENDING); + + return loading; + }); + } + } + + private void* load_thread() { + var icon_theme = Gtk.IconTheme.get_default(); + + foreach (var context in icon_theme.list_contexts()) { + if (!disabled_contexts.contains(context)) { + foreach (var icon in icon_theme.list_icons(context)) { + IconContext icon_context = IconContext.OTHER; + switch(context) { + case "Apps": case "Applications": + icon_context = IconContext.APPS; break; + case "Emotes": + icon_context = IconContext.EMOTES; break; + case "Places": case "Devices": + icon_context = IconContext.PLACES; break; + case "Mimetypes": + icon_context = IconContext.FILES; break; + case "Actions": + icon_context = IconContext.ACTIONS; break; + default: break; + } + + try { + var new_entry = new ListEntry(); + new_entry.name = icon; + new_entry.context = icon_context; + new_entry.pixbuf = icon_theme.load_icon(icon, 32, 0); + + // some icons have only weird sizes... do not include them + if (new_entry.pixbuf.width == 32) + this.load_queue.push(new_entry); + + } catch (GLib.Error e) { + warning("Failed to load image " + icon); + } + } + } + } + + this.loading = false; + + if (spinner != null) + spinner.visible = this.loading; + + return null; + } +} + +} diff --git a/src/gui/indicator.vala b/src/gui/indicator.vala new file mode 100644 index 0000000..8033cb7 --- /dev/null +++ b/src/gui/indicator.vala @@ -0,0 +1,160 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// An appindicator sitting in the panel. It owns the settings menu. +///////////////////////////////////////////////////////////////////////// + +public class Indicator : GLib.Object { + + ///////////////////////////////////////////////////////////////////// + /// The internally used indicator. + ///////////////////////////////////////////////////////////////////// + + #if HAVE_APPINDICATOR + private AppIndicator.Indicator indicator { private get; private set; } + #else + private Gtk.StatusIcon indicator {private get; private set; } + private Gtk.Menu menu {private get; private set; } + #endif + + ///////////////////////////////////////////////////////////////////// + /// The Preferences Menu of Gnome-Pie. + ///////////////////////////////////////////////////////////////////// + + private Preferences prefs { private get; private set; } + + ///////////////////////////////////////////////////////////////////// + /// Returns true, when the indicator is currently visible. + ///////////////////////////////////////////////////////////////////// + + public bool active { + get { + + #if HAVE_APPINDICATOR + return indicator.get_status() == AppIndicator.IndicatorStatus.ACTIVE; + #else + return indicator.get_visible(); + #endif + } + set { + #if HAVE_APPINDICATOR + if (value) indicator.set_status(AppIndicator.IndicatorStatus.ACTIVE); + else indicator.set_status(AppIndicator.IndicatorStatus.PASSIVE); + #else + indicator.set_visible(value); + #endif + } + } + + ///////////////////////////////////////////////////////////////////// + /// C'tor, constructs a new Indicator, residing in the user's panel. + ///////////////////////////////////////////////////////////////////// + + public Indicator() { + #if HAVE_APPINDICATOR + string path = ""; + string icon = "indicator-applet"; + try { + path = GLib.Path.get_dirname(GLib.FileUtils.read_link("/proc/self/exe"))+"/resources"; + icon = "gnome-pie-indicator"; + } catch (GLib.FileError e) { + warning("Failed to get path of executable!"); + } + + this.indicator = new AppIndicator.Indicator.with_path("Gnome-Pie", icon, + AppIndicator.IndicatorCategory.APPLICATION_STATUS, path); + var menu = new Gtk.Menu(); + #else + this.indicator = new Gtk.StatusIcon(); + try { + var file = GLib.File.new_for_path(GLib.Path.build_filename( + GLib.Path.get_dirname(GLib.FileUtils.read_link("/proc/self/exe"))+"/resources", + "gnome-pie-indicator.svg" + )); + + if (!file.query_exists()) + this.indicator.set_from_icon_name("gnome-pie-indicator"); + else + this.indicator.set_from_file(file.get_path()); + } catch (GLib.FileError e) { + warning("Failed to get path of executable!"); + this.indicator.set_from_icon_name("gnome-pie-indicator"); + } + + this.menu = new Gtk.Menu(); + var menu = this.menu; + #endif + + this.prefs = new Preferences(); + + // preferences item + var item = new Gtk.ImageMenuItem.from_stock (Gtk.Stock.PREFERENCES, null); + item.activate.connect(() => { + this.prefs.show(); + }); + + item.show(); + menu.append(item); + + // about item + item = new Gtk.ImageMenuItem.from_stock (Gtk.Stock.ABOUT, null); + item.show(); + item.activate.connect(() => { + var about = new GnomePieAboutDialog(); + about.run(); + about.destroy(); + }); + menu.append(item); + + // separator + var sepa = new Gtk.SeparatorMenuItem(); + sepa.show(); + menu.append(sepa); + + // quit item + item = new Gtk.ImageMenuItem.from_stock(Gtk.Stock.QUIT, null); + item.activate.connect(Gtk.main_quit); + item.show(); + menu.append(item); + + #if HAVE_APPINDICATOR + this.indicator.set_menu(menu); + #else + this.indicator.popup_menu.connect((btn, time) => { + this.menu.popup(null, null, null, btn, time); + }); + #endif + + this.active = Config.global.show_indicator; + Config.global.notify["show-indicator"].connect((s, p) => { + this.active = Config.global.show_indicator; + }); + } + + ///////////////////////////////////////////////////////////////////// + /// Shows the preferences menu. + ///////////////////////////////////////////////////////////////////// + + public void show_preferences() { + this.prefs.show(); + } +} + +} diff --git a/src/gui/pieList.vala b/src/gui/pieList.vala new file mode 100644 index 0000000..df6135a --- /dev/null +++ b/src/gui/pieList.vala @@ -0,0 +1,1018 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +// A very complex Widget. This is by far the most ugly file of this project +// but well, this list *is* complex... sorry ;) + +class PieList : Gtk.TreeView { + + private Gtk.ListStore groups; + private Gtk.ListStore pies; + private Gtk.ListStore actions; + private Gtk.TreeStore data; + + private const int small_icon = 24; + private const int large_icon = 36; + + // data positions in the data ListStore + private enum DataPos {IS_QUICKACTION, ICON, NAME, TYPE_ID, ACTION_TYPE, + ICON_PIXBUF, FONT_WEIGHT, ICON_NAME_EDITABLE, QUICKACTION_VISIBLE, QUICKACTION_ACTIVATABLE, + TYPE_VISIBLE, GROUP_VISIBLE, APP_VISIBLE, KEY_VISIBLE, PIE_VISIBLE, + URI_VISIBLE, DISPLAY_COMMAND_GROUP, DISPLAY_COMMAND_APP, + DISPLAY_COMMAND_KEY, DISPLAY_COMMAND_PIE, DISPLAY_COMMAND_URI, + REAL_COMMAND_GROUP, REAL_COMMAND_PIE, REAL_COMMAND_KEY} + + // data positions in the actions ListStore + private enum ActionPos {NAME, TYPE, CAN_QUICKACTION, ICON_NAME_EDITABLE} + + // data positions in the pies ListStore + private enum PiePos {NAME, ID} + + // data positions in the groups ListStore + private enum GroupPos {NAME, TYPE, ICON} + + public PieList() { + GLib.Object(); + + Gtk.TreeIter last; + + // group choices + this.groups = new Gtk.ListStore(3, typeof(string), // group name + typeof(string), // group type + typeof(string)); // group icon + + // add all registered group types + foreach (var type in GroupRegistry.types) { + this.groups.append(out last); + this.groups.set(last, GroupPos.NAME, GroupRegistry.names[type], + GroupPos.TYPE, type.name(), + GroupPos.ICON, GroupRegistry.icons[type]); + } + + // pie choices + this.pies = new Gtk.ListStore(2, typeof(string), // pie name + typeof(string)); // pie id + + // action type choices + this.actions = new Gtk.ListStore(4, typeof(string), // type name + typeof(string), // action type + typeof(bool), // can be quickaction + typeof(bool)); // icon/name editable + + // add all registered action types + foreach (var type in ActionRegistry.types) { + this.actions.append(out last); + this.actions.set(last, ActionPos.NAME, ActionRegistry.names[type], + ActionPos.TYPE, type.name(), + ActionPos.CAN_QUICKACTION, true, + ActionPos.ICON_NAME_EDITABLE, ActionRegistry.icon_name_editables[type]); + } + // and one type for groups + this.actions.append(out last); + this.actions.set(last, ActionPos.NAME, _("Slice group"), + ActionPos.TYPE, typeof(ActionGroup).name(), + ActionPos.CAN_QUICKACTION, false, + ActionPos.ICON_NAME_EDITABLE, false); + + // main data model + this.data = new Gtk.TreeStore(24, typeof(bool), // is quickaction + typeof(string), // icon + typeof(string), // name + typeof(string), // slice: type label, pie: "ID: %id" + typeof(string), // typeof(action), typeof(ActionGroup).name() if group action, pie_id if Pie + + typeof(Gdk.Pixbuf), // icon pixbuf + typeof(int), // font weight + + typeof(bool), // icon/name editable + + typeof(bool), // quickaction visible + typeof(bool), // quickaction activatable + typeof(bool), // type visible + typeof(bool), // group renderer visible + typeof(bool), // app renderer visible + typeof(bool), // key renderer visible + typeof(bool), // pie renderer visible + typeof(bool), // uri renderer visible + + typeof(string), // display command group + typeof(string), // display command app + typeof(string), // display command key + typeof(string), // display command pie + typeof(string), // display command uri + + typeof(string), // real command group + typeof(string), // real command pie + typeof(string)); // real command key + + + this.set_model(this.data); + this.set_grid_lines(Gtk.TreeViewGridLines.NONE); + this.set_enable_tree_lines(false); + this.set_reorderable(false); + this.set_level_indentation(-10); + + // create the gui + // icon column + var icon_column = new Gtk.TreeViewColumn(); + icon_column.title = _("Icon"); + icon_column.expand = false; + + // quickaction checkbox + var check_render = new Gtk.CellRendererToggle(); + check_render.activatable = true; + check_render.radio = true; + check_render.width = 15; + + check_render.toggled.connect((path) => { + Gtk.TreeIter toggled; + this.data.get_iter_from_string(out toggled, path); + + bool current = false; + this.data.get(toggled, DataPos.IS_QUICKACTION, out current); + + // set all others off + Gtk.TreeIter parent; + this.data.iter_parent(out parent, toggled); + string parent_pos = this.data.get_string_from_iter(parent); + int child_count = this.data.iter_n_children(parent); + + for (int i=0; i { + Gtk.TreeIter iter; + this.data.get_iter_from_string(out iter, path); + int icon_size = this.data.iter_depth(iter) == 0 ? this.large_icon : this.small_icon; + + this.data.set(iter, DataPos.ICON, icon_name); + this.data.set(iter, DataPos.ICON_PIXBUF, this.load_icon(icon_name, icon_size)); + + this.update_pie(iter); + this.update_linked(); + }); + + icon_column.pack_start(icon_render, false); + icon_column.add_attribute(icon_render, "icon_name", DataPos.ICON); + icon_column.add_attribute(icon_render, "pixbuf", DataPos.ICON_PIXBUF); + icon_column.add_attribute(icon_render, "editable", DataPos.ICON_NAME_EDITABLE); + icon_column.add_attribute(icon_render, "icon_sensitive", DataPos.ICON_NAME_EDITABLE); + + // command column + var command_column = new Gtk.TreeViewColumn(); + command_column.title = _("Command"); + command_column.resizable = true; + + // slice group + var command_renderer_group = new Gtk.CellRendererCombo(); + command_renderer_group.editable = true; + command_renderer_group.has_entry = false; + command_renderer_group.text_column = 0; + command_renderer_group.ellipsize = Pango.EllipsizeMode.END; + command_renderer_group.model = this.groups; + + command_renderer_group.changed.connect((path, iter) => { + string display_name; + string type; + string icon; + + this.groups.get(iter, GroupPos.NAME, out display_name); + this.groups.get(iter, GroupPos.TYPE, out type); + this.groups.get(iter, GroupPos.ICON, out icon); + + Gtk.TreeIter data_iter; + this.data.get_iter_from_string(out data_iter, path); + + this.data.set(data_iter, DataPos.DISPLAY_COMMAND_GROUP, display_name); + this.data.set(data_iter, DataPos.REAL_COMMAND_GROUP, type); + this.data.set(data_iter, DataPos.NAME, display_name); + this.data.set(data_iter, DataPos.ICON, icon); + + this.update_pie(data_iter); + }); + + command_column.pack_end(command_renderer_group, true); + command_column.add_attribute(command_renderer_group, "weight", DataPos.FONT_WEIGHT); + command_column.add_attribute(command_renderer_group, "text", DataPos.DISPLAY_COMMAND_GROUP); + command_column.add_attribute(command_renderer_group, "visible", DataPos.GROUP_VISIBLE); + + + // app action + var command_renderer_app = new Gtk.CellRendererText(); + command_renderer_app.editable = true; + command_renderer_app.ellipsize = Pango.EllipsizeMode.END; + + command_renderer_app.edited.connect((path, command) => { + Gtk.TreeIter data_iter; + this.data.get_iter_from_string(out data_iter, path); + + this.data.set(data_iter, DataPos.DISPLAY_COMMAND_APP, command); + + this.update_pie(data_iter); + }); + + command_column.pack_end(command_renderer_app, true); + command_column.add_attribute(command_renderer_app, "weight", DataPos.FONT_WEIGHT); + command_column.add_attribute(command_renderer_app, "text", DataPos.DISPLAY_COMMAND_APP); + command_column.add_attribute(command_renderer_app, "visible", DataPos.APP_VISIBLE); + + + // key action + var command_renderer_key = new Gtk.CellRendererAccel(); + command_renderer_key.editable = true; + command_renderer_key.ellipsize = Pango.EllipsizeMode.END; + + command_renderer_key.accel_edited.connect((path, key, mods) => { + Gtk.TreeIter data_iter; + this.data.get_iter_from_string(out data_iter, path); + + string label = Gtk.accelerator_get_label(key, mods); + string accelerator = Gtk.accelerator_name(key, mods); + + this.data.set(data_iter, DataPos.DISPLAY_COMMAND_KEY, label); + this.data.set(data_iter, DataPos.REAL_COMMAND_KEY, accelerator); + + this.update_pie(data_iter); + }); + + command_renderer_key.accel_cleared.connect((path) => { + Gtk.TreeIter data_iter; + this.data.get_iter_from_string(out data_iter, path); + + this.data.set(data_iter, DataPos.DISPLAY_COMMAND_KEY, _("Not bound")); + this.data.set(data_iter, DataPos.REAL_COMMAND_KEY, ""); + + this.update_pie(data_iter); + }); + + command_column.pack_end(command_renderer_key, true); + command_column.add_attribute(command_renderer_key, "weight", DataPos.FONT_WEIGHT); + command_column.add_attribute(command_renderer_key, "text", DataPos.DISPLAY_COMMAND_KEY); + command_column.add_attribute(command_renderer_key, "visible", DataPos.KEY_VISIBLE); + + + // pie action + var command_renderer_pie = new Gtk.CellRendererCombo(); + command_renderer_pie.editable = true; + command_renderer_pie.has_entry = false; + command_renderer_pie.text_column = 0; + command_renderer_pie.ellipsize = Pango.EllipsizeMode.END; + command_renderer_pie.model = this.pies; + + command_renderer_pie.changed.connect((path, iter) => { + string name; + string id; + + this.pies.get(iter, PiePos.NAME, out name); + this.pies.get(iter, PiePos.ID, out id); + + Gtk.TreeIter data_iter; + this.data.get_iter_from_string(out data_iter, path); + + this.data.set(data_iter, DataPos.DISPLAY_COMMAND_PIE, name); + this.data.set(data_iter, DataPos.REAL_COMMAND_PIE, id); + + this.update_pie(data_iter); + this.update_linked(); + }); + + command_column.pack_end(command_renderer_pie, true); + command_column.add_attribute(command_renderer_pie, "weight", DataPos.FONT_WEIGHT); + command_column.add_attribute(command_renderer_pie, "text", DataPos.DISPLAY_COMMAND_PIE); + command_column.add_attribute(command_renderer_pie, "visible", DataPos.PIE_VISIBLE); + + + // uri action + var command_renderer_uri = new Gtk.CellRendererText(); + command_renderer_uri.editable = true; + command_renderer_uri.ellipsize = Pango.EllipsizeMode.END; + + command_renderer_uri.edited.connect((path, uri) => { + Gtk.TreeIter data_iter; + this.data.get_iter_from_string(out data_iter, path); + + this.data.set(data_iter, DataPos.DISPLAY_COMMAND_URI, uri); + + this.update_pie(data_iter); + }); + + command_column.pack_end(command_renderer_uri, true); + command_column.add_attribute(command_renderer_uri, "weight", DataPos.FONT_WEIGHT); + command_column.add_attribute(command_renderer_uri, "text", DataPos.DISPLAY_COMMAND_URI); + command_column.add_attribute(command_renderer_uri, "visible", DataPos.URI_VISIBLE); + + + // type column + var type_column = new Gtk.TreeViewColumn(); + type_column.title = _("Pie-ID / Action type"); + type_column.resizable = true; + + var type_render = new Gtk.CellRendererCombo(); + type_render.editable = true; + type_render.has_entry = false; + type_render.model = actions; + type_render.text_column = 0; + type_render.ellipsize = Pango.EllipsizeMode.END; + + // change command_render's visibility accordingly + type_render.changed.connect((path, iter) => { + string text = ""; + string type; + bool can_quickaction; + bool icon_name_editable; + + this.actions.get(iter, ActionPos.NAME, out text); + this.actions.get(iter, ActionPos.TYPE, out type); + this.actions.get(iter, ActionPos.CAN_QUICKACTION, out can_quickaction); + this.actions.get(iter, ActionPos.ICON_NAME_EDITABLE, out icon_name_editable); + + Gtk.TreeIter data_iter; + this.data.get_iter_from_string(out data_iter, path); + + this.data.set(data_iter, DataPos.TYPE_ID, text); + this.data.set(data_iter, DataPos.ACTION_TYPE, type); + this.data.set(data_iter, DataPos.QUICKACTION_ACTIVATABLE, can_quickaction); + this.data.set(data_iter, DataPos.ICON_NAME_EDITABLE, icon_name_editable); + + // set all command renderes invisible + this.data.set(data_iter, DataPos.GROUP_VISIBLE, false); + this.data.set(data_iter, DataPos.APP_VISIBLE, false); + this.data.set(data_iter, DataPos.KEY_VISIBLE, false); + this.data.set(data_iter, DataPos.PIE_VISIBLE, false); + this.data.set(data_iter, DataPos.URI_VISIBLE, false); + + // set one visible + int type_id = 0; + if(type == typeof(AppAction).name()) type_id = 1; + else if(type == typeof(KeyAction).name()) type_id = 2; + else if(type == typeof(PieAction).name()) type_id = 3; + else if(type == typeof(UriAction).name()) type_id = 4; + else type_id = 0; + + this.data.set(data_iter, DataPos.GROUP_VISIBLE + type_id, true); + + this.update_linked(); + this.update_pie(data_iter); + + //this.set_cursor(new Gtk.TreePath.from_string(path), command_column, true); + }); + + type_column.pack_start(type_render, true); + type_column.add_attribute(type_render, "sensitive", DataPos.TYPE_VISIBLE); + type_column.add_attribute(type_render, "editable", DataPos.TYPE_VISIBLE); + type_column.add_attribute(type_render, "text", DataPos.TYPE_ID); + + // name column + var name_column = new Gtk.TreeViewColumn(); + name_column.title = _("Name"); + name_column.expand = true; + name_column.resizable = true; + + var name_render = new Gtk.CellRendererText(); + name_render.editable = true; + name_render.ellipsize = Pango.EllipsizeMode.END; + + name_render.edited.connect((path, text) => { + Gtk.TreeIter iter; + this.data.get_iter_from_string(out iter, path); + + this.data.set(iter, DataPos.NAME, text); + + // try to change icon to a fitting one + string icon; + this.data.get(iter, DataPos.ICON, out icon); + if (icon == "application-default-icon" && Gtk.IconTheme.get_default().has_icon(text.down())) { + this.data.set(iter, DataPos.ICON, text.down()); + } + + this.update_pie(iter); + this.update_linked(); + + //this.set_cursor(new Gtk.TreePath.from_string(path), type_column, true); + }); + + name_column.pack_start(name_render, true); + name_column.add_attribute(name_render, "weight", DataPos.FONT_WEIGHT); + name_column.add_attribute(name_render, "text", DataPos.NAME); + name_column.add_attribute(name_render, "sensitive", DataPos.ICON_NAME_EDITABLE); + name_column.add_attribute(name_render, "editable", DataPos.ICON_NAME_EDITABLE); + + this.append_column(icon_column); + this.append_column(name_column); + this.append_column(type_column); + this.append_column(command_column); + + this.realize.connect(this.load); + + // context menu + var menu = new Gtk.Menu(); + + var item = new Gtk.ImageMenuItem.with_label(_("Add new Pie")); + item.set_image(new Gtk.Image.from_stock(Gtk.Stock.ADD, Gtk.IconSize.MENU)); + item.activate.connect(this.add_empty_pie); + menu.append(item); + + item = new Gtk.ImageMenuItem.with_label(_("Add new Slice")); + item.set_image(new Gtk.Image.from_stock(Gtk.Stock.ADD, Gtk.IconSize.MENU)); + item.activate.connect(this.add_empty_slice); + menu.append(item); + + var sepa = new Gtk.SeparatorMenuItem(); + menu.append(sepa); + + item = new Gtk.ImageMenuItem.with_label(_("Delete")); + item.set_image(new Gtk.Image.from_stock(Gtk.Stock.DELETE, Gtk.IconSize.MENU)); + item.activate.connect(this.delete_selection); + menu.append(item); + + menu.show_all(); + + this.button_press_event.connect((event) => { + if (event.type == Gdk.EventType.BUTTON_PRESS && event.button == 3) { + menu.popup(null, null, null, event.button, event.time); + } + return false; + }); + + // setup drag'n'drop + Gtk.TargetEntry uri_source = {"text/uri-list", 0, 0}; + Gtk.TargetEntry[] entries = { uri_source }; + + this.drag_data_received.connect(this.on_dnd_received); + this.drag_data_get.connect(this.on_dnd_source); + this.enable_model_drag_dest(entries, Gdk.DragAction.COPY | Gdk.DragAction.MOVE | Gdk.DragAction.LINK); + + this.get_selection().changed.connect(() => { + Gtk.TreeIter selected; + if (this.get_selection().get_selected(null, out selected)) { + if (this.data.iter_depth(selected) == 0) { + this.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, entries, Gdk.DragAction.LINK); + } else { + this.unset_rows_drag_source(); + } + } + }); + + this.drag_begin.connect(() => { + this.unset_rows_drag_dest(); + }); + + this.drag_end.connect(() => { + this.enable_model_drag_dest(entries, Gdk.DragAction.COPY | Gdk.DragAction.MOVE | Gdk.DragAction.LINK); + }); + } + + // moves the selected slice up + public void selection_up() { + Gtk.TreeIter selected; + if (this.get_selection().get_selected(null, out selected)) { + Gtk.TreePath path = this.data.get_path(selected); + Gtk.TreeIter? before = null;; + if (path.prev() && this.data.get_iter(out before, path)) { + this.data.swap(selected, before); + this.get_selection().changed(); + this.update_pie(selected); + } + } + } + + // moves the selected slice down + public void selection_down() { + Gtk.TreeIter selected; + if (this.get_selection().get_selected(null, out selected)) { + Gtk.TreePath path = this.data.get_path(selected); + Gtk.TreeIter? after = null; + path.next(); + if (this.data.get_iter(out after, path)) { + this.data.swap(selected, after); + this.get_selection().changed(); + this.update_pie(selected); + } + } + } + + // updates the entire list, checking for changed cross-references via PieActions + // updates their names and icons if needed + private void update_linked() { + this.data.foreach((model, path, iter) => { + string action_type; + this.data.get(iter, DataPos.ACTION_TYPE, out action_type); + + if (action_type == typeof(PieAction).name()) { + string command; + this.data.get(iter, DataPos.REAL_COMMAND_PIE, out command); + + var referee = PieManager.all_pies[command]; + + if (referee != null) { + this.data.set(iter, DataPos.ICON, referee.icon); + this.data.set(iter, DataPos.NAME, referee.name); + this.data.set(iter, DataPos.ICON_PIXBUF, this.load_icon(referee.icon, this.small_icon)); + this.data.set(iter, DataPos.DISPLAY_COMMAND_PIE, referee.name); + } else { + // referenced Pie does not exist anymore or no is selected; + // select the first one... + Gtk.TreeIter first_pie; + this.pies.get_iter_first(out first_pie); + + string name; + string id; + + this.pies.get(first_pie, PiePos.NAME, out name); + this.pies.get(first_pie, PiePos.ID, out id); + + this.data.set(iter, DataPos.DISPLAY_COMMAND_PIE, name); + this.data.set(iter, DataPos.REAL_COMMAND_PIE, id); + + update_linked(); + } + } else if (action_type == typeof(ActionGroup).name()) { + string command; + this.data.get(iter, DataPos.REAL_COMMAND_GROUP, out command); + + if (command == "") { + // no group is selected, select the first one... + Gtk.TreeIter first_group; + this.groups.get_iter_first(out first_group); + + string name; + string type; + string icon; + + this.groups.get(first_group, GroupPos.NAME, out name); + this.groups.get(first_group, GroupPos.TYPE, out type); + this.groups.get(first_group, GroupPos.ICON, out icon); + + this.data.set(iter, DataPos.DISPLAY_COMMAND_GROUP, name); + this.data.set(iter, DataPos.NAME, name); + this.data.set(iter, DataPos.REAL_COMMAND_GROUP, type); + this.data.set(iter, DataPos.ICON, icon); + } + } + + return false; + }); + } + + // adds a new, empty pie to the list + private void add_empty_pie() { + var new_one = PieManager.create_persistent_pie(_("New Pie"), "application-default-icon", ""); + + Gtk.TreeIter last; + this.pies.append(out last); this.pies.set(last, 0, new_one.name, 1, new_one.id); + + Gtk.TreeIter parent; + this.data.append(out parent, null); + this.data.set(parent, DataPos.IS_QUICKACTION, false, + DataPos.ICON, new_one.icon, + DataPos.NAME, new_one.name, + DataPos.TYPE_ID, "ID: " + new_one.id, + DataPos.ACTION_TYPE, new_one.id, + DataPos.ICON_PIXBUF, this.load_icon(new_one.icon, this.large_icon), + DataPos.FONT_WEIGHT, 800, + DataPos.ICON_NAME_EDITABLE, true, + DataPos.QUICKACTION_VISIBLE, false, + DataPos.QUICKACTION_ACTIVATABLE, false, + DataPos.TYPE_VISIBLE, false, + DataPos.GROUP_VISIBLE, false, + DataPos.APP_VISIBLE, false, + DataPos.KEY_VISIBLE, true, + DataPos.PIE_VISIBLE, false, + DataPos.URI_VISIBLE, false, + DataPos.DISPLAY_COMMAND_GROUP, "", + DataPos.DISPLAY_COMMAND_APP, "", + DataPos.DISPLAY_COMMAND_KEY, PieManager.get_accelerator_label_of(new_one.id), + DataPos.DISPLAY_COMMAND_PIE, "", + DataPos.DISPLAY_COMMAND_URI, "", + DataPos.REAL_COMMAND_GROUP, "", + DataPos.REAL_COMMAND_PIE, "", + DataPos.REAL_COMMAND_KEY, PieManager.get_accelerator_of(new_one.id)); + + + this.get_selection().select_iter(parent); + this.scroll_to_cell(this.data.get_path(parent), null, true, 0.5f, 0.0f); + } + + // adds a new empty slice to the list + private void add_empty_slice() { + Gtk.TreeIter selected; + if (this.get_selection().get_selected(null, out selected)) { + var path = this.data.get_path(selected); + if (path != null) { + if (path.get_depth() == 2) + this.data.iter_parent(out selected, selected); + + this.load_action(selected, new AppAction(_("New Action"), "application-default-icon", "")); + + Gtk.TreeIter new_one; + this.data.iter_nth_child(out new_one, selected, this.data.iter_n_children(selected)-1); + this.expand_to_path(this.data.get_path(new_one)); + this.get_selection().select_iter(new_one); + this.scroll_to_cell(this.data.get_path(new_one), null, true, 0.5f, 0.0f); + + this.update_pie(selected); + } + } else { + var dialog = new Gtk.MessageDialog((Gtk.Window)this.get_toplevel(), Gtk.DialogFlags.MODAL, + Gtk.MessageType.INFO, + Gtk.ButtonsType.CLOSE, + _("You have to select a Pie to add a Slice to!")); + dialog.run(); + dialog.destroy(); + } + } + + // writes the contents of action to the position pointed by slice + private void write_action(Action action, Gtk.TreeIter slice) { + this.data.set(slice, DataPos.IS_QUICKACTION, action.is_quick_action, + DataPos.ICON, action.icon, + DataPos.NAME, action.name, + DataPos.TYPE_ID, ActionRegistry.names[action.get_type()], + DataPos.ACTION_TYPE, action.get_type().name(), + DataPos.ICON_PIXBUF, this.load_icon(action.icon, this.small_icon), + DataPos.FONT_WEIGHT, 400, + DataPos.ICON_NAME_EDITABLE, !(action is PieAction), + DataPos.QUICKACTION_VISIBLE, true, + DataPos.QUICKACTION_ACTIVATABLE, true, + DataPos.TYPE_VISIBLE, true, + DataPos.GROUP_VISIBLE, false, + DataPos.APP_VISIBLE, action is AppAction, + DataPos.KEY_VISIBLE, action is KeyAction, + DataPos.PIE_VISIBLE, action is PieAction, + DataPos.URI_VISIBLE, action is UriAction, + DataPos.DISPLAY_COMMAND_GROUP, "", + DataPos.DISPLAY_COMMAND_APP, (action is AppAction) ? action.display_command : "", + DataPos.DISPLAY_COMMAND_KEY, (action is KeyAction) ? action.display_command : _("Not bound"), + DataPos.DISPLAY_COMMAND_PIE, (action is PieAction) ? action.display_command : "", + DataPos.DISPLAY_COMMAND_URI, (action is UriAction) ? action.display_command : "", + DataPos.REAL_COMMAND_GROUP, "", + DataPos.REAL_COMMAND_PIE, (action is PieAction) ? action.real_command : "", + DataPos.REAL_COMMAND_KEY, (action is KeyAction) ? action.real_command : ""); + } + + // deletes the currently selected pie or slice + private void delete_selection() { + Gtk.TreeIter selected; + if (this.get_selection().get_selected(null, out selected)) { + var path = this.data.get_path(selected); + if (path != null) { + if (path.get_depth() == 1) + this.delete_pie(selected); + else + this.delete_slice(selected); + } + } else { + var dialog = new Gtk.MessageDialog((Gtk.Window)this.get_toplevel(), Gtk.DialogFlags.MODAL, + Gtk.MessageType.INFO, + Gtk.ButtonsType.CLOSE, + _("You have to select a Pie or a Slice to delete!")); + dialog.run(); + dialog.destroy(); + } + } + + // deletes the given pie + private void delete_pie(Gtk.TreeIter pie) { + var dialog = new Gtk.MessageDialog((Gtk.Window)this.get_toplevel(), Gtk.DialogFlags.MODAL, + Gtk.MessageType.QUESTION, + Gtk.ButtonsType.YES_NO, + _("Do you really want to delete the selected Pie with all contained Slices?")); + + dialog.response.connect((response) => { + if (response == Gtk.ResponseType.YES) { + string id; + this.data.get(pie, DataPos.ACTION_TYPE, out id); + this.data.remove(pie); + PieManager.remove_pie(id); + + this.pies.foreach((model, path, iter) => { + string pies_id; + this.pies.get(iter, PiePos.ID, out pies_id); + + if (id == pies_id) { + this.pies.remove(iter); + return true; + } + + return false; + }); + + this.update_linked(); + } + }); + + dialog.run(); + dialog.destroy(); + } + + // deletes the given slice + private void delete_slice(Gtk.TreeIter slice) { + var dialog = new Gtk.MessageDialog((Gtk.Window)this.get_toplevel(), Gtk.DialogFlags.MODAL, + Gtk.MessageType.QUESTION, + Gtk.ButtonsType.YES_NO, + _("Do you really want to delete the selected Slice?")); + + dialog.response.connect((response) => { + if (response == Gtk.ResponseType.YES) { + Gtk.TreeIter parent; + this.data.iter_parent(out parent, slice); + this.data.remove(slice); + this.update_pie(parent); + } + }); + + dialog.run(); + dialog.destroy(); + } + + // loads all pies to the list + private void load() { + foreach (var pie in PieManager.all_pies.entries) { + this.load_pie(pie.value); + } + } + + // loads one given pie to the list + private void load_pie(Pie pie) { + if (pie.id.length == 3) { + + Gtk.TreeIter last; + this.pies.append(out last); this.pies.set(last, PiePos.NAME, pie.name, + PiePos.ID, pie.id); + + Gtk.TreeIter parent; + this.data.append(out parent, null); + this.data.set(parent, DataPos.IS_QUICKACTION, false, + DataPos.ICON, pie.icon, + DataPos.NAME, pie.name, + DataPos.TYPE_ID, "ID: " + pie.id, + DataPos.ACTION_TYPE, pie.id, + DataPos.ICON_PIXBUF, this.load_icon(pie.icon, this.large_icon), + DataPos.FONT_WEIGHT, 800, + DataPos.ICON_NAME_EDITABLE, true, + DataPos.QUICKACTION_VISIBLE, false, + DataPos.QUICKACTION_ACTIVATABLE, false, + DataPos.TYPE_VISIBLE, false, + DataPos.GROUP_VISIBLE, false, + DataPos.APP_VISIBLE, false, + DataPos.KEY_VISIBLE, true, + DataPos.PIE_VISIBLE, false, + DataPos.URI_VISIBLE, false, + DataPos.DISPLAY_COMMAND_GROUP, "", + DataPos.DISPLAY_COMMAND_APP, "", + DataPos.DISPLAY_COMMAND_KEY, PieManager.get_accelerator_label_of(pie.id), + DataPos.DISPLAY_COMMAND_PIE, "", + DataPos.DISPLAY_COMMAND_URI, "", + DataPos.REAL_COMMAND_GROUP, "", + DataPos.REAL_COMMAND_PIE, "", + DataPos.REAL_COMMAND_KEY, PieManager.get_accelerator_of(pie.id)); + + foreach (var group in pie.action_groups) { + this.load_group(parent, group); + } + } + } + + // loads a given group + private void load_group(Gtk.TreeIter parent, ActionGroup group) { + if (group.get_type() == typeof(ActionGroup)) { + foreach (var action in group.actions) { + this.load_action(parent, action); + } + } else { + Gtk.TreeIter child; + this.data.append(out child, parent); + this.data.set(child, DataPos.IS_QUICKACTION, false, + DataPos.ICON, GroupRegistry.icons[group.get_type()], + DataPos.NAME, GroupRegistry.names[group.get_type()], + DataPos.TYPE_ID, _("Slice group"), + DataPos.ACTION_TYPE, typeof(ActionGroup).name(), + DataPos.ICON_PIXBUF, this.load_icon(GroupRegistry.icons[group.get_type()], this.small_icon), + DataPos.FONT_WEIGHT, 400, + DataPos.ICON_NAME_EDITABLE, false, + DataPos.QUICKACTION_VISIBLE, true, + DataPos.QUICKACTION_ACTIVATABLE, false, + DataPos.TYPE_VISIBLE, true, + DataPos.GROUP_VISIBLE, true, + DataPos.APP_VISIBLE, false, + DataPos.KEY_VISIBLE, false, + DataPos.PIE_VISIBLE, false, + DataPos.URI_VISIBLE, false, + DataPos.DISPLAY_COMMAND_GROUP, GroupRegistry.names[group.get_type()], + DataPos.DISPLAY_COMMAND_APP, "", + DataPos.DISPLAY_COMMAND_KEY, _("Not bound"), + DataPos.DISPLAY_COMMAND_PIE, "", + DataPos.DISPLAY_COMMAND_URI, "", + DataPos.REAL_COMMAND_GROUP, group.get_type().name(), + DataPos.REAL_COMMAND_PIE, "", + DataPos.REAL_COMMAND_KEY, ""); + } + } + + // loads a given slice + private void load_action(Gtk.TreeIter parent, Action action) { + Gtk.TreeIter child; + this.data.append(out child, parent); + this.write_action(action, child); + } + + // applies all changes done to the given pie + private void update_pie(Gtk.TreeIter slice_or_pie) { + // get pie iter + var path = this.data.get_path(slice_or_pie); + if (path != null) { + var pie = slice_or_pie; + if (path.get_depth() == 2) + this.data.iter_parent(out pie, slice_or_pie); + + // get information on pie + string id; + string icon; + string name; + string hotkey; + + this.data.get(pie, DataPos.ICON, out icon); + this.data.get(pie, DataPos.NAME, out name); + this.data.get(pie, DataPos.ACTION_TYPE, out id); + this.data.get(pie, DataPos.REAL_COMMAND_KEY, out hotkey); + + // remove pie + PieManager.remove_pie(id); + + this.pies.foreach((model, path, iter) => { + string pies_id; + this.pies.get(iter, PiePos.ID, out pies_id); + + if (id == pies_id) { + this.pies.set(iter, PiePos.NAME, name); + return true; + } + + return false; + }); + + // create new pie + var new_pie = PieManager.create_persistent_pie(name, icon, hotkey, id); + + // add actions accordingly + if (this.data.iter_has_child(pie)) { + Gtk.TreeIter child; + this.data.iter_children(out child, pie); + + do { + // get slice information + string slice_type; + string slice_icon; + string slice_name; + bool is_quick_action; + + this.data.get(child, DataPos.ICON, out slice_icon); + this.data.get(child, DataPos.NAME, out slice_name); + this.data.get(child, DataPos.ACTION_TYPE, out slice_type); + this.data.get(child, DataPos.IS_QUICKACTION, out is_quick_action); + + if (slice_type == typeof(AppAction).name()) { + string slice_command; + this.data.get(child, DataPos.DISPLAY_COMMAND_APP, out slice_command); + var group = new ActionGroup(new_pie.id); + group.add_action(new AppAction(slice_name, slice_icon, slice_command, is_quick_action)); + new_pie.add_group(group); + } else if (slice_type == typeof(KeyAction).name()) { + string slice_command; + this.data.get(child, DataPos.REAL_COMMAND_KEY, out slice_command); + var group = new ActionGroup(new_pie.id); + group.add_action(new KeyAction(slice_name, slice_icon, slice_command, is_quick_action)); + new_pie.add_group(group); + } else if (slice_type == typeof(PieAction).name()) { + string slice_command; + this.data.get(child, DataPos.REAL_COMMAND_PIE, out slice_command); + var group = new ActionGroup(new_pie.id); + group.add_action(new PieAction(slice_command, is_quick_action)); + new_pie.add_group(group); + } else if (slice_type == typeof(UriAction).name()) { + string slice_command; + this.data.get(child, DataPos.DISPLAY_COMMAND_URI, out slice_command); + var group = new ActionGroup(new_pie.id); + group.add_action(new UriAction(slice_name, slice_icon, slice_command, is_quick_action)); + new_pie.add_group(group); + } else if (slice_type == typeof(ActionGroup).name()) { + string slice_command; + this.data.get(child, DataPos.REAL_COMMAND_GROUP, out slice_command); + + var group = GLib.Object.new(GLib.Type.from_name(slice_command), "parent_id", new_pie.id); + new_pie.add_group(group as ActionGroup); + } + + } while (this.data.iter_next(ref child)); + } + } + } + + // creates new action when the list receives a drag'n'drop event + private void on_dnd_received(Gdk.DragContext context, int x, int y, Gtk.SelectionData selection_data, uint info, uint time_) { + string[] uris = selection_data.get_uris(); + + Gtk.TreePath path; + Gtk.TreeViewDropPosition pos; + + // check for valid position + if (!this.get_dest_row_at_pos(x, y, out path, out pos) + || (path.to_string() == "0" && pos == Gtk.TreeViewDropPosition.BEFORE)) { + + warning("Failed to insert Slice: Invalid location!"); + return; + } + + // get position to insert (when child: after, when parent: as first child) + Gtk.TreeIter parent; + int insert_pos = 0; + if (path.get_depth() == 1) { + if (pos == Gtk.TreeViewDropPosition.BEFORE) { + path.prev(); + this.data.get_iter(out parent, path); + insert_pos = this.data.iter_n_children(parent); + } else { + this.data.get_iter(out parent, path); + } + } else { + if (pos == Gtk.TreeViewDropPosition.BEFORE) { + insert_pos = path.get_indices()[1]; + } else { + insert_pos = path.get_indices()[1]+1; + } + + path.up(); + this.data.get_iter(out parent, path); + } + + foreach (var uri in uris) { + Gtk.TreeIter new_child; + this.data.insert(out new_child, parent, insert_pos); + this.write_action(ActionRegistry.new_for_uri(uri), new_child); + } + + this.update_pie(parent); + } + + private void on_dnd_source(Gdk.DragContext context, Gtk.SelectionData selection_data, uint info, uint time_) { + Gtk.TreeIter selected; + if (this.get_selection().get_selected(null, out selected)) { + string id = ""; + this.data.get(selected, DataPos.ACTION_TYPE, out id); + selection_data.set_uris({"file://" + Paths.launchers + "/" + id + ".desktop"}); + } + } + + private Gdk.Pixbuf load_icon(string name, int size) { + Gdk.Pixbuf pixbuf = null; + + try { + if (name.contains("/")) + pixbuf = new Gdk.Pixbuf.from_file_at_size(name, size, size); + else + pixbuf = new Gdk.Pixbuf.from_file_at_size(Icon.get_icon_file(name, size), size, size); + } catch (GLib.Error e) { + warning(e.message); + } + + return pixbuf; + } +} + +} diff --git a/src/gui/preferences.vala b/src/gui/preferences.vala new file mode 100644 index 0000000..f43fd4a --- /dev/null +++ b/src/gui/preferences.vala @@ -0,0 +1,338 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// The Gtk settings menu of Gnome-Pie. +///////////////////////////////////////////////////////////////////////// + +public class Preferences : Gtk.Window { + + ///////////////////////////////////////////////////////////////////// + /// C'tor, constructs the whole dialog. Many thanks to the + /// synapse-project, since some of this code is taken from there! + ///////////////////////////////////////////////////////////////////// + + public Preferences() { + this.title = _("Gnome-Pie - Settings"); + this.set_position(Gtk.WindowPosition.CENTER); + this.set_size_request(550, 550); + this.resizable = false; + this.icon_name = "gnome-pie"; + this.delete_event.connect(hide_on_delete); + + // main container + var main_vbox = new Gtk.VBox(false, 12); + main_vbox.border_width = 12; + add(main_vbox); + + // tab container + var tabs = new Gtk.Notebook(); + + // general tab + var general_tab = new Gtk.VBox(false, 6); + general_tab.border_width = 12; + + // behavior frame + var behavior_frame = new Gtk.Frame(null); + behavior_frame.set_shadow_type(Gtk.ShadowType.NONE); + var behavior_frame_label = new Gtk.Label(null); + behavior_frame_label.set_markup(Markup.printf_escaped ("%s", _("Behavior"))); + behavior_frame.set_label_widget(behavior_frame_label); + + var behavior_vbox = new Gtk.VBox (false, 6); + var align = new Gtk.Alignment (0.5f, 0.5f, 1.0f, 1.0f); + align.set_padding (6, 12, 12, 12); + align.add (behavior_vbox); + behavior_frame.add (align); + + // Autostart checkbox + var autostart = new Gtk.CheckButton.with_label (_("Startup on Login")); + autostart.tooltip_text = _("If checked, Gnome-Pie will start when you log in."); + autostart.active = Config.global.auto_start; + autostart.toggled.connect(autostart_toggled); + behavior_vbox.pack_start(autostart, false); + + // Indicator icon + var indicator = new Gtk.CheckButton.with_label (_("Show Indicator")); + indicator.tooltip_text = _("If checked, an indicator for easy access of the settings menu is shown in your panel."); + indicator.active = Config.global.show_indicator; + indicator.toggled.connect(indicator_toggled); + behavior_vbox.pack_start(indicator, false); + + // Open Pies at Mouse + var open_at_mouse = new Gtk.CheckButton.with_label (_("Open Pies at Mouse")); + open_at_mouse.tooltip_text = _("If checked, pies will open at your pointer. Otherwise they'll pop up in the middle of the screen."); + open_at_mouse.active = Config.global.open_at_mouse; + open_at_mouse.toggled.connect(open_at_mouse_toggled); + behavior_vbox.pack_start(open_at_mouse, false); + + // Click to activate + var click_to_activate = new Gtk.CheckButton.with_label (_("Turbo mode")); + click_to_activate.tooltip_text = _("If checked, the pie closes when its keystroke is released. The currently hovered slice gets executed. This allows very fast selection but disables keyboard navigation."); + click_to_activate.active = Config.global.turbo_mode; + click_to_activate.toggled.connect(turbo_mode_toggled); + behavior_vbox.pack_start(click_to_activate, false); + + // Slider + var slider_hbox = new Gtk.HBox (false, 6); + behavior_vbox.pack_start(slider_hbox); + + var scale_label = new Gtk.Label(_("Global Scale")); + slider_hbox.pack_start(scale_label, false, false); + + var scale_slider = new Gtk.HScale.with_range(0.5, 2.0, 0.05); + scale_slider.set_value(Config.global.global_scale); + scale_slider.value_pos = Gtk.PositionType.RIGHT; + + bool changing = false; + bool changed_again = false; + + scale_slider.value_changed.connect(() => { + if (!changing) { + changing = true; + Timeout.add(300, () => { + if (changed_again) { + changed_again = false; + return true; + } + + Config.global.global_scale = scale_slider.get_value(); + Config.global.load_themes(Config.global.theme.name); + changing = false; + return false; + }); + } else { + changed_again = true; + } + }); + + slider_hbox.pack_end(scale_slider, true, true); + + general_tab.pack_start (behavior_frame, false); + + // theme frame + var theme_frame = new Gtk.Frame(null); + theme_frame.set_shadow_type(Gtk.ShadowType.NONE); + var theme_frame_label = new Gtk.Label(null); + theme_frame_label.set_markup(Markup.printf_escaped("%s", _("Themes"))); + theme_frame.set_label_widget(theme_frame_label); + + // scrollable frame + var scroll = new Gtk.ScrolledWindow (null, null); + align = new Gtk.Alignment(0.5f, 0.5f, 1.0f, 1.0f); + align.set_padding(6, 12, 12, 12); + align.add(scroll); + theme_frame.add(align); + + scroll.set_policy (Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + scroll.set_shadow_type (Gtk.ShadowType.IN); + + // themes list + var theme_list = new ThemeList(); + scroll.add(theme_list); + + general_tab.pack_start (theme_frame, true, true); + tabs.append_page(general_tab, new Gtk.Label(_("General"))); + + // pies tab + var pies_tab = new Gtk.VBox(false, 6); + pies_tab.border_width = 12; + tabs.append_page(pies_tab, new Gtk.Label(_("Pies"))); + + // scrollable frame + scroll = new Gtk.ScrolledWindow (null, null); + align = new Gtk.Alignment(0.5f, 0.5f, 1.0f, 1.0f); + align.add(scroll); + pies_tab.add(align); + + scroll.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + scroll.set_shadow_type (Gtk.ShadowType.IN); + + // pies list + var pie_list = new PieList(); + scroll.add(pie_list); + + // bottom box + var info_box = new Gtk.HBox (false, 6); + + // info image + var info_image = new Gtk.Image.from_stock (Gtk.Stock.INFO, Gtk.IconSize.MENU); + info_box.pack_start (info_image, false); + + // info label + var info_label = new TipViewer({ + _("You can right-click in the list for adding or removing entries."), + _("You can reset Gnome-Pie to its default options with the terminal command \"gnome-pie --reset\"."), + _("The radiobutton at the beginning of each slice-line indicates the QuickAction of the pie."), + _("Pies can be opened with the terminal command \"gnome-pie --open=ID\"."), + _("Feel free to visit Gnome-Pie's homepage at %s!").printf("gnome-pie.simonschneegans.de"), + _("You can drag'n'drop applications from your main menu to the list above."), + _("If you want to give some feedback, please write an e-mail to %s!").printf("code@simonschneegans.de"), + _("You may drag'n'drop URLs and bookmarks from your internet browser to the list above."), + _("Bugs can be reported at %s!").printf("Github"), + _("It's possible to drag'n'drop files and folders from your file browser to the list above."), + _("In order to create a launcher for a Pie, drag the Pie from the list to your desktop!") + }); + this.show.connect(info_label.start_slide_show); + this.hide.connect(info_label.stop_slide_show); + + info_box.pack_start (info_label); + + // down Button + var down_button = new Gtk.Button(); + down_button.tooltip_text = _("Moves the selected Slice down"); + down_button.sensitive = false; + var down_image = new Gtk.Image.from_stock (Gtk.Stock.GO_DOWN, Gtk.IconSize.LARGE_TOOLBAR); + down_button.add(down_image); + down_button.clicked.connect (() => { + pie_list.selection_down(); + }); + + info_box.pack_end(down_button, false, false); + + // up Button + var up_button = new Gtk.Button(); + up_button.tooltip_text = _("Moves the selected Slice up"); + up_button.sensitive = false; + var up_image = new Gtk.Image.from_stock (Gtk.Stock.GO_UP, Gtk.IconSize.LARGE_TOOLBAR); + up_button.add(up_image); + up_button.clicked.connect (() => { + pie_list.selection_up(); + }); + + info_box.pack_end(up_button, false, false); + + pie_list.get_selection().changed.connect(() => { + Gtk.TreeIter selected; + if (pie_list.get_selection().get_selected(null, out selected)) { + Gtk.TreePath path = pie_list.model.get_path(selected); + if (path.get_depth() == 1) { + up_button.sensitive = false; + down_button.sensitive = false; + } else { + up_button.sensitive = true; + down_button.sensitive = true; + + int child_pos = path.get_indices()[1]; + + if (child_pos == 0) + up_button.sensitive = false; + + path.up(); + Gtk.TreeIter parent_iter; + pie_list.model.get_iter(out parent_iter, path); + if (child_pos == pie_list.model.iter_n_children(parent_iter)-1) + down_button.sensitive = false; + + } + } + }); + + pies_tab.pack_start (info_box, false); + + main_vbox.pack_start(tabs); + + // close button + var bbox = new Gtk.HButtonBox (); + bbox.set_layout (Gtk.ButtonBoxStyle.END); + var close_button = new Gtk.Button.from_stock (Gtk.Stock.CLOSE); + close_button.clicked.connect (() => { + hide(); + // save settings on close + Config.global.save(); + Pies.save(); + }); + bbox.pack_start (close_button); + + main_vbox.pack_start(bbox, false); + + main_vbox.show_all(); + } + + ///////////////////////////////////////////////////////////////////// + /// Creates or deletes the autostart file. This code is inspired + /// by project synapse as well. + ///////////////////////////////////////////////////////////////////// + + private void autostart_toggled(Gtk.ToggleButton check_box) { + bool active = check_box.active; + if (!active && FileUtils.test(Paths.autostart, FileTest.EXISTS)) { + // delete the autostart file + FileUtils.remove (Paths.autostart); + } + else if (active && !FileUtils.test(Paths.autostart, FileTest.EXISTS)) { + string autostart_entry = + "#!/usr/bin/env xdg-open\n" + + "[Desktop Entry]\n" + + "Name=Gnome-Pie\n" + + "Exec=gnome-pie\n" + + "Encoding=UTF-8\n" + + "Type=Application\n" + + "X-GNOME-Autostart-enabled=true\n" + + "Icon=gnome-pie\n"; + + // create the autostart file + string autostart_dir = GLib.Path.get_dirname(Paths.autostart); + if (!FileUtils.test(autostart_dir, FileTest.EXISTS | FileTest.IS_DIR)) { + DirUtils.create_with_parents(autostart_dir, 0755); + } + + try { + FileUtils.set_contents(Paths.autostart, autostart_entry); + FileUtils.chmod(Paths.autostart, 0755); + } catch (Error e) { + var d = new Gtk.MessageDialog (this, 0, Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, + "%s", e.message); + d.run (); + d.destroy (); + } + } + } + + ///////////////////////////////////////////////////////////////////// + /// Shows or hides the indicator. + ///////////////////////////////////////////////////////////////////// + + private void indicator_toggled(Gtk.ToggleButton check_box) { + var check = check_box as Gtk.CheckButton; + Config.global.show_indicator = check.active; + } + + ///////////////////////////////////////////////////////////////////// + /// Toggles whether the Pies are shown at the mouse or in the middle + /// of the screen. + ///////////////////////////////////////////////////////////////////// + + private void open_at_mouse_toggled(Gtk.ToggleButton check_box) { + var check = check_box as Gtk.CheckButton; + Config.global.open_at_mouse = check.active; + } + + ///////////////////////////////////////////////////////////////////// + /// Toggles whether the user has to click with the mouse in order to + /// activate a slice. + ///////////////////////////////////////////////////////////////////// + + private void turbo_mode_toggled(Gtk.ToggleButton check_box) { + var check = check_box as Gtk.CheckButton; + Config.global.turbo_mode = check.active; + } +} + +} diff --git a/src/gui/themeList.vala b/src/gui/themeList.vala new file mode 100644 index 0000000..7eadcdb --- /dev/null +++ b/src/gui/themeList.vala @@ -0,0 +1,95 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A widget displaying all available themes of Gnome-Pie. +///////////////////////////////////////////////////////////////////////// + +class ThemeList : Gtk.TreeView { + + ///////////////////////////////////////////////////////////////////// + /// The currently selected row. + ///////////////////////////////////////////////////////////////////// + + private Gtk.TreeIter active { private get; private set; } + + ///////////////////////////////////////////////////////////////////// + /// C'tor, constructs the Widget. + ///////////////////////////////////////////////////////////////////// + + public ThemeList() { + GLib.Object(); + + var data = new Gtk.ListStore(2, typeof(bool), // selected + typeof(string)); // description + base.set_model(data); + base.set_headers_visible(false); + base.set_rules_hint(true); + base.set_grid_lines(Gtk.TreeViewGridLines.NONE); + + var main_column = new Gtk.TreeViewColumn(); + var check_render = new Gtk.CellRendererToggle(); + check_render.set_radio(true); + check_render.set_activatable(true); + main_column.pack_start(check_render, false); + + // switch the theme if the entry has been toggled + check_render.toggled.connect((r, path) => { + Gtk.TreeIter toggled; + data.get_iter(out toggled, new Gtk.TreePath.from_string(path)); + + if (toggled != this.active) { + Timeout.add(10, () => { + int index = int.parse(path); + Config.global.theme = Config.global.themes[index]; + Config.global.theme.load(); + Config.global.theme.load_images(); + return false; + }); + + data.set(this.active, 0, false); + data.set(toggled, 0, true); + + this.active = toggled; + } + }); + + var theme_render = new Gtk.CellRendererText(); + main_column.pack_start(theme_render, true); + + base.append_column(main_column); + + main_column.add_attribute(check_render, "active", 0); + main_column.add_attribute(theme_render, "markup", 1); + + // load all themes into the list + var themes = Config.global.themes; + foreach(var theme in themes) { + Gtk.TreeIter current; + data.append(out current); + data.set(current, 0, theme == Config.global.theme); + data.set(current, 1, "" + theme.name + "\n" + theme.description + + " - " + _("by") + " " + theme.author + ""); + if(theme == Config.global.theme) + this.active = current; + } + } +} + +} diff --git a/src/gui/tipViewer.vala b/src/gui/tipViewer.vala new file mode 100644 index 0000000..c653dd9 --- /dev/null +++ b/src/gui/tipViewer.vala @@ -0,0 +1,172 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A widget showing tips. The tips are beautifully faded in and out. +///////////////////////////////////////////////////////////////////////// + +public class TipViewer : Gtk.Label { + + ///////////////////////////////////////////////////////////////////// + /// Some settings tweaking the behavior of the TipViewer. + ///////////////////////////////////////////////////////////////////// + + private const double fade_time = 0.5; + private const double frame_rate = 20.0; + private const double delay = 7.0; + + ///////////////////////////////////////////////////////////////////// + /// False, if the playback of tips is stopped. + ///////////////////////////////////////////////////////////////////// + + private bool playing = false; + + ///////////////////////////////////////////////////////////////////// + /// An array containing all tips. + ///////////////////////////////////////////////////////////////////// + + private string[] tips; + + ///////////////////////////////////////////////////////////////////// + /// The index of the currently displayed tip. + ///////////////////////////////////////////////////////////////////// + + private int index = -1; + + ///////////////////////////////////////////////////////////////////// + /// Colors of the font and the background. Used for fading effects. + ///////////////////////////////////////////////////////////////////// + + private Gdk.Color fg; + private Gdk.Color bg; + + ///////////////////////////////////////////////////////////////////// + /// The fading value. + ///////////////////////////////////////////////////////////////////// + + private AnimatedValue alpha; + + ///////////////////////////////////////////////////////////////////// + /// C'tor, initializes all members and sets the basic layout. + ///////////////////////////////////////////////////////////////////// + + public TipViewer(string[] tips) { + this.tips = tips; + this.fg = this.get_style().fg[0]; + this.bg = this.get_style().bg[0]; + + this.alpha = new AnimatedValue.linear(1.0, 0.0, this.fade_time); + + this.set_alignment (0.0f, 0.5f); + this.wrap = true; + this.set_use_markup(true); + this.modify_font(Pango.FontDescription.from_string("9")); + + this.set_random_tip(); + } + + ///////////////////////////////////////////////////////////////////// + /// Starts the playback of tips. + ///////////////////////////////////////////////////////////////////// + + public void start_slide_show() { + if (!this.playing && tips.length > 1) { + this.playing = true; + GLib.Timeout.add((uint)(this.delay*1000.0), () => { + this.fade_out(); + + GLib.Timeout.add((uint)(1000.0*this.fade_time), () => { + this.set_random_tip(); + this.fade_in(); + return false; + }); + + return this.playing; + }); + } + } + + ///////////////////////////////////////////////////////////////////// + /// Stops the playback of tips. + ///////////////////////////////////////////////////////////////////// + + public void stop_slide_show() { + this.playing = false; + } + + ///////////////////////////////////////////////////////////////////// + /// Starts the fading in. + ///////////////////////////////////////////////////////////////////// + + private void fade_in() { + this.alpha = new AnimatedValue.linear(this.alpha.val, 1.0, this.fade_time); + + GLib.Timeout.add((uint)(1000.0/this.frame_rate), () => { + this.alpha.update(1.0/this.frame_rate); + this.update_label(); + + return (this.alpha.val != 1.0); + }); + } + + ///////////////////////////////////////////////////////////////////// + /// Starts the fading out. + ///////////////////////////////////////////////////////////////////// + + private void fade_out() { + this.alpha = new AnimatedValue.linear(this.alpha.val, 0.0, this.fade_time); + + GLib.Timeout.add((uint)(1000.0/this.frame_rate), () => { + this.alpha.update(1.0/this.frame_rate); + this.update_label(); + + return (this.alpha.val != 0.0); + }); + } + + ///////////////////////////////////////////////////////////////////// + /// Updates the color of the label. Called every frame while fading. + ///////////////////////////////////////////////////////////////////// + + private void update_label() { + Gdk.Color color = {(uint32)(fg.pixel*this.alpha.val + bg.pixel*(1.0 - this.alpha.val)), + (uint16)(fg.red*this.alpha.val + bg.red*(1.0 - this.alpha.val)), + (uint16)(fg.green*this.alpha.val + bg.green*(1.0 - this.alpha.val)), + (uint16)(fg.blue*this.alpha.val + bg.blue*(1.0 - this.alpha.val))}; + + this.modify_fg(Gtk.StateType.NORMAL, color); + } + + ///////////////////////////////////////////////////////////////////// + /// Chooses the next random tip. + ///////////////////////////////////////////////////////////////////// + + private void set_random_tip() { + if (tips.length > 1) { + int next_index = -1; + do { + next_index = GLib.Random.int_range(0, tips.length); + } while (next_index == this.index); + this.index = next_index; + this.label = tips[this.index]; + } + } +} + +} diff --git a/src/pies/defaultConfig.vala b/src/pies/defaultConfig.vala new file mode 100644 index 0000000..bd981b5 --- /dev/null +++ b/src/pies/defaultConfig.vala @@ -0,0 +1,70 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A helper class which creates a user-specific default configuration. +///////////////////////////////////////////////////////////////////////// + +namespace Pies { + + public void create_default_config() { + + // add a pie with playback controls + var multimedia = PieManager.create_persistent_pie(_("Multimedia"), "stock_media-play", "m"); + multimedia.add_action(new KeyAction(_("Next Track"), "stock_media-next", "XF86AudioNext", true)); + multimedia.add_action(new KeyAction(_("Stop"), "stock_media-stop", "XF86AudioStop")); + multimedia.add_action(new KeyAction(_("Previous Track"), "stock_media-prev", "XF86AudioPrev")); + multimedia.add_action(new KeyAction(_("Play/Pause"), "stock_media-play", "XF86AudioPlay")); + + // add a pie with the users default applications + var apps = PieManager.create_persistent_pie(_("Applications"), "applications-accessories", "a"); + apps.add_action(ActionRegistry.default_for_mime_type("text/plain")); + apps.add_action(ActionRegistry.default_for_mime_type("audio/ogg")); + apps.add_action(ActionRegistry.default_for_mime_type("video/ogg")); + apps.add_action(ActionRegistry.default_for_mime_type("image/jpg")); + apps.add_action(ActionRegistry.default_for_uri("http")); + apps.add_action(ActionRegistry.default_for_uri("mailto")); + + // add a pie with the users bookmarks and devices + var bookmarks = PieManager.create_persistent_pie(_("Bookmarks"), "user-bookmarks", "b"); + bookmarks.add_group(new BookmarkGroup(bookmarks.id)); + bookmarks.add_group(new DevicesGroup(bookmarks.id)); + + // add a pie with session controls + var session = PieManager.create_persistent_pie(_("Session"), "gnome-session-halt", "q"); + session.add_group(new SessionGroup(session.id)); + + // add a pie with a main menu + var menu = PieManager.create_persistent_pie(_("Main Menu"), "alacarte", "space"); + menu.add_group(new MenuGroup(menu.id)); + + // add a pie with window controls + var window = PieManager.create_persistent_pie(_("Window"), "gnome-window-manager", "w"); + window.add_action(new KeyAction(_("Scale"), "top", "s")); + window.add_action(new KeyAction(_("Minimize"), "bottom", "F9", true)); + window.add_action(new KeyAction(_("Close"), "window-close", "F4")); + window.add_action(new KeyAction(_("Maximize"), "window_fullscreen", "F10")); + window.add_action(new KeyAction(_("Restore"), "window_nofullscreen", "F5")); + + // save the configuration to file + Pies.save(); + } +} + +} diff --git a/src/pies/load.vala b/src/pies/load.vala new file mode 100644 index 0000000..912ddf0 --- /dev/null +++ b/src/pies/load.vala @@ -0,0 +1,230 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +using GLib.Math; + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A helper method which loads pies according to the configuration file. +///////////////////////////////////////////////////////////////////////// + +namespace Pies { + + ///////////////////////////////////////////////////////////////////// + /// Loads all Pies from the pies.conf file. + ///////////////////////////////////////////////////////////////////// + + public void load() { + // check whether the config file exists + if (!GLib.File.new_for_path(Paths.pie_config).query_exists()) { + message("Creating new configuration file in \"" + Paths.pie_config + "\"."); + Pies.create_default_config(); + return; + } + + // load the settings file + Xml.Parser.init(); + Xml.Doc* piesXML = Xml.Parser.parse_file(Paths.pie_config); + + if (piesXML != null) { + // begin parsing at the root element + Xml.Node* root = piesXML->get_root_element(); + if (root != null) { + for (Xml.Node* node = root->children; node != null; node = node->next) { + if (node->type == Xml.ElementType.ELEMENT_NODE) { + string node_name = node->name.down(); + switch (node_name) { + case "pie": + parse_pie(node); + break; + default: + warning("Invalid child element <" + node_name + "> in element pies.conf!"); + break; + } + } + } + Xml.Parser.cleanup(); + + } else { + warning("Error loading pies: pies.conf is empty! The cake is a lie..."); + } + + delete piesXML; + + } else { + warning("Error loading pies: pies.conf not found! The cake is a lie..."); + } + } + + ///////////////////////////////////////////////////////////////////// + /// Parses a element from the pies.conf file. + ///////////////////////////////////////////////////////////////////// + + private static void parse_pie(Xml.Node* node) { + string hotkey = ""; + string name = ""; + string icon = ""; + string id = ""; + int quick_action = -1; + + // parse all attributes of this node + for (Xml.Attr* attribute = node->properties; attribute != null; attribute = attribute->next) { + string attr_name = attribute->name.down(); + string attr_content = attribute->children->content; + + switch (attr_name) { + case "hotkey": + hotkey = attr_content; + break; + case "quickaction": + quick_action = int.parse(attr_content); + break; + case "name": + name = attr_content; + break; + case "icon": + icon = attr_content; + break; + case "id": + id = attr_content; + break; + default: + warning("Invalid setting \"" + attr_name + "\" in pies.conf!"); + break; + } + } + + if (name == "") { + warning("Invalid element in pies.conf: No name specified!"); + return; + } + + // add a new Pie with the loaded properties + var pie = PieManager.create_persistent_pie(name, icon, hotkey, id); + + // and parse all child elements + for (Xml.Node* slice = node->children; slice != null; slice = slice->next) { + if (slice->type == Xml.ElementType.ELEMENT_NODE) { + string node_name = slice->name.down(); + switch (node_name) { + case "slice": + parse_slice(slice, pie); + break; + case "group": + parse_group(slice, pie); + break; + default: + warning("Invalid child element <" + node_name + "> in element in pies.conf!"); + break; + } + } + } + } + + ///////////////////////////////////////////////////////////////////// + /// Parses a element from the pies.conf file. + ///////////////////////////////////////////////////////////////////// + + private static void parse_slice(Xml.Node* slice, Pie pie) { + string name=""; + string icon=""; + string command=""; + string type=""; + bool quick_action = false; + + // parse all attributes of this node + for (Xml.Attr* attribute = slice->properties; attribute != null; attribute = attribute->next) { + string attr_name = attribute->name.down(); + string attr_content = attribute->children->content; + + switch (attr_name) { + case "name": + name = attr_content; + break; + case "icon": + icon = attr_content; + break; + case "command": + command = attr_content; + break; + case "type": + type = attr_content; + break; + case "quickaction": + quick_action = bool.parse(attr_content); + break; + default: + warning("Invalid attribute \"" + attr_name + "\" in element in pies.conf!"); + break; + } + } + + Action action = null; + + // create a new Action according to the loaded type + foreach (var action_type in ActionRegistry.types) { + if (ActionRegistry.settings_names[action_type] == type) { + + action = GLib.Object.new(action_type, "name", name, + "icon", icon, + "real_command", command, + "is_quick_action", quick_action) as Action; + break; + } + } + + if (action != null) pie.add_action(action); + } + + ///////////////////////////////////////////////////////////////////// + /// Parses a element from the pies.conf file. + ///////////////////////////////////////////////////////////////////// + + private static void parse_group(Xml.Node* slice, Pie pie) { + string type=""; + + // parse all attributes of this node + for (Xml.Attr* attribute = slice->properties; attribute != null; attribute = attribute->next) { + string attr_name = attribute->name.down(); + string attr_content = attribute->children->content; + + switch (attr_name) { + case "type": + type = attr_content; + break; + default: + warning("Invalid attribute \"" + attr_name + "\" in element in pies.conf!"); + break; + } + } + + ActionGroup group = null; + + // create a new ActionGroup according to the loaded type + foreach (var group_type in GroupRegistry.types) { + if (GroupRegistry.settings_names[group_type] == type) { + group = GLib.Object.new(group_type, "parent_id", pie.id) as ActionGroup; + break; + } + } + + if (group != null) pie.add_group(group); + } +} + +} diff --git a/src/pies/pie.vala b/src/pies/pie.vala new file mode 100644 index 0000000..0f87d8f --- /dev/null +++ b/src/pies/pie.vala @@ -0,0 +1,96 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// This class stores information on a pie. A pie consists of a name, an +/// icon name and an unique ID. Furthermore it has an arbitrary amount +/// of ActionGroups storing Actions. +///////////////////////////////////////////////////////////////////////// + +public class Pie : GLib.Object { + + ///////////////////////////////////////////////////////////////////// + /// The name of this Pie. It has not to be unique. + ///////////////////////////////////////////////////////////////////// + + public string name { get; construct; } + + ///////////////////////////////////////////////////////////////////// + /// The name of the icon to be used for this Pie. It should exist in + /// the users current icon theme, else a standard icon will be used. + ///////////////////////////////////////////////////////////////////// + + public string icon { get; construct; } + + ///////////////////////////////////////////////////////////////////// + /// The ID of this Pie. It has to be unique among all Pies. This ID + /// consists of three digits when the Pie was created by the user, + /// of four digits when it was created dynamically by another class, + /// for example by an ActionGroup. + ///////////////////////////////////////////////////////////////////// + + public string id { get; construct; } + + ///////////////////////////////////////////////////////////////////// + /// Stores all ActionGroups of this Pie. + ///////////////////////////////////////////////////////////////////// + + public Gee.ArrayList action_groups { get; private set; } + + ///////////////////////////////////////////////////////////////////// + /// C'tor, initializes all given members. + ///////////////////////////////////////////////////////////////////// + + public Pie(string id, string name, string icon) { + GLib.Object(id: id, name: name, icon:icon); + + this.action_groups = new Gee.ArrayList(); + } + + ///////////////////////////////////////////////////////////////////// + /// Should be called when this Pie is deleted, in order to clean up + /// stuff created by contained ActionGroups. + ///////////////////////////////////////////////////////////////////// + + public virtual void on_remove() { + foreach (var action_group in action_groups) + action_group.on_remove(); + } + + ///////////////////////////////////////////////////////////////////// + /// Adds an Action to this Pie. + ///////////////////////////////////////////////////////////////////// + + public void add_action(Action action) { + var group = new ActionGroup(this.id); + group.add_action(action); + this.add_group(group); + } + + ///////////////////////////////////////////////////////////////////// + /// Adds an ActionGroup to this Pie. + ///////////////////////////////////////////////////////////////////// + + public void add_group(ActionGroup group) { + this.action_groups.add(group); + } +} + +} + diff --git a/src/pies/pieManager.vala b/src/pies/pieManager.vala new file mode 100644 index 0000000..eb031d0 --- /dev/null +++ b/src/pies/pieManager.vala @@ -0,0 +1,231 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A static class which stores all Pies. It can be used to add, delete +/// and open Pies. +///////////////////////////////////////////////////////////////////////// + +public class PieManager : GLib.Object { + + ///////////////////////////////////////////////////////////////////// + /// A map of all Pies. It contains both, dynamic and persistent Pies. + /// They are associated to their ID's. + ///////////////////////////////////////////////////////////////////// + + public static Gee.HashMap all_pies { get; private set; } + + ///////////////////////////////////////////////////////////////////// + /// Stores all global hotkeys. + ///////////////////////////////////////////////////////////////////// + + private static BindingManager bindings; + + ///////////////////////////////////////////////////////////////////// + /// True, if any pie has the current focus. If it is closing this + /// will be false already. + ///////////////////////////////////////////////////////////////////// + + private static bool a_pie_is_opened = false; + + ///////////////////////////////////////////////////////////////////// + /// Initializes all Pies. They are loaded from the pies.conf file. + ///////////////////////////////////////////////////////////////////// + + public static void init() { + all_pies = new Gee.HashMap(); + bindings = new BindingManager(); + + // load all Pies from th pies.conf file + Pies.load(); + + // open the according pie if it's hotkey is pressed + bindings.on_press.connect((id) => { + open_pie(id); + }); + } + + ///////////////////////////////////////////////////////////////////// + /// Opens the Pie with the given ID, if it exists. + ///////////////////////////////////////////////////////////////////// + + public static void open_pie(string id) { + if (!a_pie_is_opened) { + Pie? pie = all_pies[id]; + + if (pie != null) { + a_pie_is_opened = true; + + var window = new PieWindow(); + window.load_pie(pie); + window.open(); + + window.on_closing.connect(() => { + a_pie_is_opened = false; + }); + } else { + warning("Failed to open pie with ID \"" + id + "\": ID does not exist!"); + } + } + } + + ///////////////////////////////////////////////////////////////////// + /// Returns the hotkey which the Pie with the given ID is bound to. + ///////////////////////////////////////////////////////////////////// + + public static string get_accelerator_of(string id) { + return bindings.get_accelerator_of(id); + } + + ///////////////////////////////////////////////////////////////////// + /// Returns a human-readable version of the hotkey which the Pie + /// with the given ID is bound to. + ///////////////////////////////////////////////////////////////////// + + public static string get_accelerator_label_of(string id) { + return bindings.get_accelerator_label_of(id); + } + + ///////////////////////////////////////////////////////////////////// + /// Returns the name of the Pie with the given ID. + ///////////////////////////////////////////////////////////////////// + + public static string get_name_of(string id) { + Pie? pie = all_pies[id]; + if (pie == null) return ""; + else return pie.name; + } + + ///////////////////////////////////////////////////////////////////// + /// Creates a new Pie which is displayed in the configuration dialog + /// and gets saved. + ///////////////////////////////////////////////////////////////////// + + public static Pie create_persistent_pie(string name, string icon_name, string hotkey, string? desired_id = null) { + Pie pie = create_pie(name, icon_name, 100, 999, desired_id); + + if (hotkey != "") bindings.bind(hotkey, pie.id); + + create_launcher(pie.id); + + return pie; + } + + ///////////////////////////////////////////////////////////////////// + /// Creates a new Pie which is not displayed in the configuration + /// dialog and is not saved. + ///////////////////////////////////////////////////////////////////// + + public static Pie create_dynamic_pie(string name, string icon_name, string? desired_id = null) { + return create_pie(name, icon_name, 1000, 9999, desired_id); + } + + ///////////////////////////////////////////////////////////////////// + /// Adds a new Pie. Can't be accesd from outer scope. Use + /// create_persistent_pie or create_dynamic_pie instead. + ///////////////////////////////////////////////////////////////////// + + private static Pie create_pie(string name, string icon_name, int min_id, int max_id, string? desired_id = null) { + var random = new GLib.Rand(); + + string final_id; + + if (desired_id == null) + final_id = random.int_range(min_id, max_id).to_string(); + else { + final_id = desired_id; + final_id.canon("0123456789", '_'); + final_id = final_id.replace("_", ""); + + int id = int.parse(final_id); + + if (id < min_id || id > max_id) { + final_id = random.int_range(min_id, max_id).to_string(); + warning("The ID for pie \"" + name + "\" should be in range %u - %u! Using \"" + final_id + "\" instead of \"" + desired_id + "\"...", min_id, max_id); + } + } + + if (all_pies.has_key(final_id)) { + var tmp = final_id; + var id_number = int.parse(final_id) + 1; + if (id_number == max_id+1) id_number = min_id; + final_id = id_number.to_string(); + warning("Trying to add pie \"" + name + "\": ID \"" + tmp + "\" already exists! Using \"" + final_id + "\" instead..."); + return create_pie(name, icon_name, min_id, max_id, final_id); + } + + Pie pie = new Pie(final_id, name, icon_name); + all_pies.set(final_id, pie); + + return pie; + } + + ///////////////////////////////////////////////////////////////////// + /// Removes the Pie with the given ID if it exists. Additionally it + /// unbinds it's global hotkey. + ///////////////////////////////////////////////////////////////////// + + public static void remove_pie(string id) { + if (all_pies.has_key(id)) { + all_pies[id].on_remove(); + all_pies.unset(id); + bindings.unbind(id); + + if (id.length == 3) + remove_launcher(id); + } + else { + warning("Failed to remove pie with ID \"" + id + "\": ID does not exist!"); + } + } + + private static void create_launcher(string id) { + if (all_pies.has_key(id)) { + Pie? pie = all_pies[id]; + + string launcher_entry = + "#!/usr/bin/env xdg-open\n" + + "[Desktop Entry]\n" + + "Name=%s\n".printf(pie.name) + + "Exec=gnome-pie -o %s\n".printf(pie.id) + + "Encoding=UTF-8\n" + + "Type=Application\n" + + "Icon=%s\n".printf(pie.icon); + + // create the launcher file + string launcher = Paths.launchers + "/%s.desktop".printf(pie.id); + + try { + FileUtils.set_contents(launcher, launcher_entry); + FileUtils.chmod(launcher, 0755); + } catch (Error e) { + warning(e.message); + } + } + } + + private static void remove_launcher(string id) { + string launcher = Paths.launchers + "/%s.desktop".printf(id); + if (FileUtils.test(launcher, FileTest.EXISTS)) { + FileUtils.remove(launcher); + } + } +} + +} diff --git a/src/pies/save.vala b/src/pies/save.vala new file mode 100644 index 0000000..d691a95 --- /dev/null +++ b/src/pies/save.vala @@ -0,0 +1,81 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +using GLib.Math; + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A helper method which saves pies in a configuration file. +///////////////////////////////////////////////////////////////////////// + +namespace Pies { + + ///////////////////////////////////////////////////////////////////// + /// Saves all Pies of the PieManager to the pies.conf file. + ///////////////////////////////////////////////////////////////////// + + public void save() { + // initializes the XML-Writer + var writer = new Xml.TextWriter.filename(Paths.pie_config); + writer.set_indent(true); + writer.start_document("1.0"); + writer.start_element("pies"); + + // iterate through all Pies + foreach (var pie_entry in PieManager.all_pies.entries) { + var pie = pie_entry.value; + + // if it's no dynamically created Pie + if (pie.id.length == 3) { + // write all attributes of the Pie + writer.start_element("pie"); + writer.write_attribute("name", pie.name); + writer.write_attribute("id", pie.id); + writer.write_attribute("icon", pie.icon); + writer.write_attribute("hotkey", PieManager.get_accelerator_of(pie.id)); + + // and all of it's Actions + foreach (var group in pie.action_groups) { + // if it's a custom ActionGroup + if (group.get_type().depth() == 2) { + foreach (var action in group.actions) { + writer.start_element("slice"); + writer.write_attribute("type", ActionRegistry.settings_names[action.get_type()]); + if (ActionRegistry.icon_name_editables[action.get_type()]) { + writer.write_attribute("name", action.name); + writer.write_attribute("icon", action.icon); + } + writer.write_attribute("command", action.real_command); + writer.write_attribute("quickAction", action.is_quick_action ? "true" : "false"); + writer.end_element(); + } + } else { + writer.start_element("group"); + writer.write_attribute("type", GroupRegistry.settings_names[group.get_type()]); + writer.end_element(); + } + } + writer.end_element(); + } + } + writer.end_element(); + writer.end_document(); + } +} + +} diff --git a/src/renderers/centerRenderer.vala b/src/renderers/centerRenderer.vala new file mode 100644 index 0000000..c30e9ce --- /dev/null +++ b/src/renderers/centerRenderer.vala @@ -0,0 +1,146 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +using GLib.Math; + +namespace GnomePie { + +// Renders the center of a Pie. + +public class CenterRenderer : GLib.Object { + + private unowned PieRenderer parent; + private unowned Image? caption; + private Color color; + + private AnimatedValue activity; + private AnimatedValue alpha; + + public CenterRenderer(PieRenderer parent) { + this.parent = parent; + this.activity = new AnimatedValue.linear(0.0, 0.0, Config.global.theme.transition_time); + this.alpha = new AnimatedValue.linear(0.0, 1.0, Config.global.theme.fade_in_time); + this.color = new Color(); + this.caption = null; + } + + public void fade_out() { + this.activity.reset_target(0.0, Config.global.theme.fade_out_time); + this.alpha.reset_target(0.0, Config.global.theme.fade_out_time); + } + + public void set_active_slice(SliceRenderer? active_slice) { + if (active_slice == null) { + this.activity.reset_target(0.0, Config.global.theme.transition_time); + } else { + this.activity.reset_target(1.0, Config.global.theme.transition_time); + this.caption = active_slice.caption; + this.color = active_slice.color; + } + } + + public void draw(double frame_time, Cairo.Context ctx, double angle, double distance) { + + var layers = Config.global.theme.center_layers; + + this.activity.update(frame_time); + this.alpha.update(frame_time); + + foreach (var layer in layers) { + + ctx.save(); + + double active_speed = (layer.active_rotation_mode == CenterLayer.RotationMode.TO_MOUSE) ? + 0.0 : layer.active_rotation_speed; + double inactive_speed = (layer.inactive_rotation_mode == CenterLayer.RotationMode.TO_MOUSE) ? + 0.0 : layer.inactive_rotation_speed; + double max_scale = layer.active_scale*this.activity.val + + layer.inactive_scale*(1.0-this.activity.val); + double max_alpha = layer.active_alpha*this.activity.val + + layer.inactive_alpha*(1.0-this.activity.val); + double colorize = ((layer.active_colorize == true) ? this.activity.val : 0.0) + + ((layer.inactive_colorize == true) ? 1.0 - this.activity.val : 0.0); + double max_rotation_speed = active_speed*this.activity.val + + inactive_speed*(1.0-this.activity.val); + CenterLayer.RotationMode rotation_mode = ((this.activity.val > 0.5) ? + layer.active_rotation_mode : layer.inactive_rotation_mode); + + if (rotation_mode == CenterLayer.RotationMode.TO_MOUSE) { + double diff = angle-layer.rotation; + max_rotation_speed = layer.active_rotation_speed*this.activity.val + + layer.inactive_rotation_speed*(1.0-this.activity.val); + double smoothy = fabs(diff) < 0.9 ? fabs(diff) + 0.1 : 1.0; + double step = max_rotation_speed*frame_time*smoothy; + + if (fabs(diff) <= step || fabs(diff) >= 2.0*PI - step) + layer.rotation = angle; + else { + if ((diff > 0 && diff < PI) || diff < -PI) layer.rotation += step; + else layer.rotation -= step; + } + + } else if (rotation_mode == CenterLayer.RotationMode.TO_ACTIVE) { + max_rotation_speed *= this.activity.val; + + double slice_angle = parent.slice_count() > 0 ? 2*PI/parent.slice_count() : 0; + double direction = (int)((angle+0.5*slice_angle) / (slice_angle))*slice_angle; + double diff = direction-layer.rotation; + double step = max_rotation_speed*frame_time; + + if (fabs(diff) <= step || fabs(diff) >= 2.0*PI - step) + layer.rotation = direction; + else { + if ((diff > 0 && diff < PI) || diff < -PI) layer.rotation += step; + else layer.rotation -= step; + } + + } else layer.rotation += max_rotation_speed*frame_time; + + layer.rotation = fmod(layer.rotation+2*PI, 2*PI); + + if (colorize > 0.0) ctx.push_group(); + + ctx.rotate(layer.rotation); + ctx.scale(max_scale, max_scale); + layer.image.paint_on(ctx, this.alpha.val*max_alpha); + + if (colorize > 0.0) { + ctx.set_operator(Cairo.Operator.ATOP); + ctx.set_source_rgb(this.color.r, this.color.g, this.color.b); + ctx.paint_with_alpha(colorize); + + ctx.set_operator(Cairo.Operator.OVER); + ctx.pop_group_to_source(); + ctx.paint(); + } + + ctx.restore(); + } + + // draw caption + if (Config.global.theme.caption && caption != null && this.activity.val > 0) { + ctx.save(); + ctx.identity_matrix(); + int pos = this.parent.get_size()/2; + ctx.translate(pos, (int)(Config.global.theme.caption_position) + pos); + caption.paint_on(ctx, this.activity.val*this.alpha.val); + ctx.restore(); + } + } +} + +} diff --git a/src/renderers/pieRenderer.vala b/src/renderers/pieRenderer.vala new file mode 100644 index 0000000..5b706f4 --- /dev/null +++ b/src/renderers/pieRenderer.vala @@ -0,0 +1,208 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +using GLib.Math; + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// This class renders a Pie. In order to accomplish that, it owns a +/// CenterRenderer and some SliceRenderers. +///////////////////////////////////////////////////////////////////////// + +public class PieRenderer : GLib.Object { + + public int quick_action { get; private set; } + public int active_slice { get; private set; } + public bool show_hotkeys { get; set; } + + private int size; + private Gee.ArrayList slices; + private CenterRenderer center; + private bool key_board_control = false; + + public PieRenderer() { + this.slices = new Gee.ArrayList(); + this.center = new CenterRenderer(this); + this.quick_action = -1; + this.active_slice = -2; + this.size = 0; + } + + public void load_pie(Pie pie) { + this.slices.clear(); + + int count = 0; + foreach (var group in pie.action_groups) { + foreach (var action in group.actions) { + var renderer = new SliceRenderer(this); + this.slices.add(renderer); + renderer.load(action, slices.size-1); + + if (action.is_quick_action) { + this.quick_action = count; + } + + ++count; + } + } + + this.set_highlighted_slice(this.quick_action); + + this.size = (int)fmax(2*Config.global.theme.radius + 2*Config.global.theme.slice_radius*Config.global.theme.max_zoom, + 2*Config.global.theme.center_radius); + + // increase size if there are many slices + if (slices.size > 0) { + this.size = (int)fmax(this.size, + (((Config.global.theme.slice_radius + Config.global.theme.slice_gap)/tan(PI/slices.size)) + + Config.global.theme.slice_radius)*2*Config.global.theme.max_zoom); + } + } + + public void activate() { + if (this.active_slice >= 0 && this.active_slice < this.slices.size) + slices[active_slice].activate(); + this.cancel(); + } + + public void cancel() { + foreach (var slice in this.slices) + slice.fade_out(); + + center.fade_out(); + } + + public void select_up() { + int bottom = this.slice_count()/4; + int top = this.slice_count()*3/4; + + if (this.active_slice == -1 || this.active_slice == bottom) + this.set_highlighted_slice(top); + else if (this.active_slice > bottom && this.active_slice < top) + this.set_highlighted_slice(this.active_slice+1); + else if (this.active_slice != top) + this.set_highlighted_slice((this.active_slice-1+this.slice_count())%this.slice_count()); + } + + public void select_down() { + int bottom = this.slice_count()/4; + int top = this.slice_count()*3/4; + + if (this.active_slice == -1 || this.active_slice == top) + this.set_highlighted_slice(bottom); + else if (this.active_slice > bottom && this.active_slice < top) + this.set_highlighted_slice(this.active_slice-1); + else if (this.active_slice != bottom) + this.set_highlighted_slice((this.active_slice+1)%this.slice_count()); + } + + public void select_left() { + int left = this.slice_count()/2; + int right = 0; + + if (this.active_slice == -1 || this.active_slice == right) + this.set_highlighted_slice(left); + else if (this.active_slice > left) + this.set_highlighted_slice(this.active_slice-1); + else if (this.active_slice < left) + this.set_highlighted_slice(this.active_slice+1); + } + + public void select_right() { + int left = this.slice_count()/2; + int right = 0; + + if (this.active_slice == -1 || this.active_slice == left) + this.set_highlighted_slice(right); + else if (this.active_slice > left) + this.set_highlighted_slice((this.active_slice+1)%this.slice_count()); + else if (this.active_slice < left && this.active_slice != right) + this.set_highlighted_slice((this.active_slice-1+this.slice_count())%this.slice_count()); + } + + public int slice_count() { + return slices.size; + } + + public int get_size() { + return size; + } + + public void draw(double frame_time, Cairo.Context ctx, int mouse_x, int mouse_y) { + double distance = sqrt(mouse_x*mouse_x + mouse_y*mouse_y); + double angle = 0.0; + + if (this.key_board_control) { + angle = 2.0*PI*this.active_slice/(double)slice_count(); + } else { + + if (distance > 0) { + angle = acos(mouse_x/distance); + if (mouse_y < 0) + angle = 2*PI - angle; + } + + int next_active_slice = this.active_slice; + + if (distance < Config.global.theme.active_radius + && this.quick_action >= 0 && this.quick_action < this.slices.size) { + + next_active_slice = this.quick_action; + angle = 2.0*PI*quick_action/(double)slice_count(); + } else if (distance > Config.global.theme.active_radius && this.slice_count() > 0) { + next_active_slice = (int)(angle*slices.size/(2*PI) + 0.5) % this.slice_count(); + } else { + next_active_slice = -1; + } + + this.set_highlighted_slice(next_active_slice); + } + + center.draw(frame_time, ctx, angle, distance); + + foreach (var slice in this.slices) + slice.draw(frame_time, ctx, angle, distance); + } + + public void on_mouse_move() { + this.key_board_control = false; + } + + public void set_highlighted_slice(int index) { + if (index != this.active_slice) { + if (index >= 0 && index < this.slice_count()) + this.active_slice = index; + else if (this.quick_action >= 0) + this.active_slice = this.quick_action; + else + this.active_slice = -1; + + SliceRenderer? active = (this.active_slice >= 0 && this.active_slice < this.slice_count()) ? + this.slices[this.active_slice] : null; + + center.set_active_slice(active); + + foreach (var slice in this.slices) + slice.set_active_slice(active); + + this.key_board_control = true; + } + } +} + +} diff --git a/src/renderers/pieWindow.vala b/src/renderers/pieWindow.vala new file mode 100644 index 0000000..c4ac2ec --- /dev/null +++ b/src/renderers/pieWindow.vala @@ -0,0 +1,263 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +using GLib.Math; + +namespace GnomePie { + +// An invisible window. Used to draw Pies onto. + +public class PieWindow : Gtk.Window { + + public signal void on_closing(); + + private PieRenderer renderer; + private bool closing = false; + private GLib.Timer timer; + + private bool has_compositing = false; + + private Image background = null; + + public PieWindow() { + this.renderer = new PieRenderer(); + + this.set_title("Gnome-Pie"); + this.set_skip_taskbar_hint(true); + this.set_skip_pager_hint(true); + this.set_keep_above(true); + this.set_type_hint(Gdk.WindowTypeHint.SPLASHSCREEN); + this.set_decorated(false); + this.set_resizable(false); + this.icon_name = "gnome-pie"; + this.set_accept_focus(false); + + if (this.screen.is_composited()) { + this.set_colormap(this.screen.get_rgba_colormap()); + this.has_compositing = true; + } + + this.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK | + Gdk.EventMask.KEY_RELEASE_MASK | + Gdk.EventMask.KEY_PRESS_MASK | + Gdk.EventMask.POINTER_MOTION_MASK); + + this.button_release_event.connect ((e) => { + if (e.button == 1) this.activate_slice(); + else this.cancel(); + return true; + }); + + // remember last pressed key in order to disable key repeat + uint last_key = 0; + this.key_press_event.connect((e) => { + if (e.keyval != last_key) { + last_key = e.keyval; + this.handle_key_press(e.keyval); + } + return true; + }); + + this.key_release_event.connect((e) => { + last_key = 0; + if (Config.global.turbo_mode) + this.activate_slice(); + else + this.handle_key_release(e.keyval); + return true; + }); + + this.motion_notify_event.connect((e) => { + this.renderer.on_mouse_move(); + return true; + }); + + this.expose_event.connect(this.draw); + } + + public void load_pie(Pie pie) { + this.renderer.load_pie(pie); + this.set_window_position(); + this.set_size_request(renderer.get_size(), renderer.get_size()); + } + + public void open() { + this.realize(); + + if (!this.has_compositing) { + int x, y, width, height; + this.get_position(out x, out y); + this.get_size(out width, out height); + this.background = new Image.capture_screen(x, y, width+1, height+1); + } + + this.show(); + this.fix_focus(); + + this.timer = new GLib.Timer(); + this.timer.start(); + this.queue_draw(); + + Timeout.add((uint)(1000.0/Config.global.refresh_rate), () => { + this.queue_draw(); + return this.visible; + }); + } + + private bool draw(Gtk.Widget da, Gdk.EventExpose event) { + // clear the window + var ctx = Gdk.cairo_create(this.window); + + if (this.has_compositing) { + ctx.set_operator (Cairo.Operator.CLEAR); + ctx.paint(); + ctx.set_operator (Cairo.Operator.OVER); + } else { + ctx.set_operator (Cairo.Operator.OVER); + ctx.set_source_surface(background.surface, -1, -1); + ctx.paint(); + } + + ctx.translate(this.width_request*0.5, this.height_request*0.5); + + double mouse_x = 0.0, mouse_y = 0.0; + this.get_pointer(out mouse_x, out mouse_y); + + double frame_time = this.timer.elapsed(); + this.timer.reset(); + + this.renderer.draw(frame_time, ctx, (int)(mouse_x - this.width_request*0.5), + (int)(mouse_y - this.height_request*0.5)); + + return true; + } + + private void activate_slice() { + if (!this.closing) { + this.closing = true; + this.on_closing(); + this.unfix_focus(); + this.renderer.activate(); + + Timeout.add((uint)(Config.global.theme.fade_out_time*1000), () => { + this.destroy(); + //ThemedIcon.clear_cache(); + return false; + }); + } + } + + private void cancel() { + if (!this.closing) { + this.closing = true; + this.on_closing(); + this.unfix_focus(); + this.renderer.cancel(); + + Timeout.add((uint)(Config.global.theme.fade_out_time*1000), () => { + this.destroy(); + //ThemedIcon.clear_cache(); + return false; + }); + } + } + + private void set_window_position() { + if(Config.global.open_at_mouse) this.set_position(Gtk.WindowPosition.MOUSE); + else this.set_position(Gtk.WindowPosition.CENTER); + } + + private void handle_key_press(uint key) { + if (Gdk.keyval_name(key) == "Escape") this.cancel(); + else if (Gdk.keyval_name(key) == "Return") this.activate_slice(); + else if (!Config.global.turbo_mode) { + if (Gdk.keyval_name(key) == "Up") this.renderer.select_up(); + else if (Gdk.keyval_name(key) == "Down") this.renderer.select_down(); + else if (Gdk.keyval_name(key) == "Left") this.renderer.select_left(); + else if (Gdk.keyval_name(key) == "Right") this.renderer.select_right(); + else if (Gdk.keyval_name(key) == "Alt_L") this.renderer.show_hotkeys = true; + else { + int index = -1; + + if (key >= 48 && key <= 57) index = (int)key - 48; + else if (key >= 97 && key <= 122) index = (int)key - 87; + else if (key >= 65 && key <= 90) index = (int)key - 55; + + if (index >= 0 && index < this.renderer.slice_count()) { + this.renderer.set_highlighted_slice(index); + + if (this.renderer.active_slice == index) { + GLib.Timeout.add((uint)(Config.global.theme.transition_time*1000.0), ()=> { + this.activate_slice(); + return false; + }); + } + + } + } + } + } + + private void handle_key_release(uint key) { + if (!Config.global.turbo_mode) { + if (Gdk.keyval_name(key) == "Alt_L") this.renderer.show_hotkeys = false; + } + } + + // utilities for grabbing focus + // Code from Gnome-Do/Synapse + private void fix_focus() { + uint32 timestamp = Gtk.get_current_event_time(); + this.present_with_time(timestamp); + this.get_window().raise(); + this.get_window().focus(timestamp); + + int i = 0; + Timeout.add(100, () => { + if (++i >= 100) return false; + return !try_grab_window(); + }); + } + + // Code from Gnome-Do/Synapse + private void unfix_focus() { + uint32 time = Gtk.get_current_event_time(); + Gdk.pointer_ungrab(time); + Gdk.keyboard_ungrab(time); + Gtk.grab_remove(this); + } + + // Code from Gnome-Do/Synapse + private bool try_grab_window() { + uint time = Gtk.get_current_event_time(); + if (Gdk.pointer_grab(this.get_window(), true, Gdk.EventMask.BUTTON_PRESS_MASK | + Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.POINTER_MOTION_MASK, + null, null, time) == Gdk.GrabStatus.SUCCESS) { + + if (Gdk.keyboard_grab(this.get_window(), true, time) == Gdk.GrabStatus.SUCCESS) { + Gtk.grab_add(this); + return true; + } else { + Gdk.pointer_ungrab(time); + return false; + } + } + return false; + } +} + +} diff --git a/src/renderers/sliceRenderer.vala b/src/renderers/sliceRenderer.vala new file mode 100644 index 0000000..08c880f --- /dev/null +++ b/src/renderers/sliceRenderer.vala @@ -0,0 +1,182 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +using GLib.Math; + +namespace GnomePie { + +// Renders a Slice of a Pie. According to the current theme. + +public class SliceRenderer : GLib.Object { + + public bool active {get; private set; default = false;} + public Image caption {get; private set;} + public Color color {get; private set;} + + private Image active_icon; + private Image inactive_icon; + private Image hotkey; + + private Action action; + + private unowned PieRenderer parent; + private int position; + + private AnimatedValue fade; + private AnimatedValue scale; + private AnimatedValue alpha; + private AnimatedValue fade_rotation; + private AnimatedValue fade_scale; + + public SliceRenderer(PieRenderer parent) { + this.parent = parent; + + this.fade = new AnimatedValue.linear(0.0, 0.0, Config.global.theme.transition_time); + this.alpha = new AnimatedValue.linear(0.0, 1.0, Config.global.theme.fade_in_time); + this.scale = new AnimatedValue.cubic(AnimatedValue.Direction.OUT, + 1.0/Config.global.theme.max_zoom, + 1.0/Config.global.theme.max_zoom, + Config.global.theme.transition_time, + Config.global.theme.springiness); + this.fade_scale = new AnimatedValue.cubic(AnimatedValue.Direction.OUT, + Config.global.theme.fade_in_zoom, 1.0, + Config.global.theme.fade_in_time, + Config.global.theme.springiness); + this.fade_rotation = new AnimatedValue.cubic(AnimatedValue.Direction.OUT, + Config.global.theme.fade_in_rotation, 0.0, + Config.global.theme.fade_in_time); + } + + public void load(Action action, int position) { + this.position = position; + this.action = action; + + + if (Config.global.theme.caption) + this.caption = new RenderedText(action.name, + Config.global.theme.caption_width, + Config.global.theme.caption_height, + Config.global.theme.caption_font); + + this.active_icon = new ThemedIcon(action.icon, true); + this.inactive_icon = new ThemedIcon(action.icon, false); + + this.color = new Color.from_icon(this.active_icon); + + string hotkey_label = ""; + if (position < 10) { + hotkey_label = "%u".printf(position); + } else if (position < 36) { + hotkey_label = "%c".printf((char)(55 + position)); + } + + this.hotkey = new RenderedText(hotkey_label, (int)Config.global.theme.slice_radius*2, + (int)Config.global.theme.slice_radius*2, "sans 20"); + } + + public void activate() { + action.activate(); + } + + public void fade_out() { + this.alpha.reset_target(0.0, Config.global.theme.fade_out_time); + this.fade_scale = new AnimatedValue.cubic(AnimatedValue.Direction.IN, + this.fade_scale.val, + Config.global.theme.fade_out_zoom, + Config.global.theme.fade_out_time, + Config.global.theme.springiness); + this.fade_rotation = new AnimatedValue.cubic(AnimatedValue.Direction.IN, + this.fade_rotation.val, + Config.global.theme.fade_out_rotation, + Config.global.theme.fade_out_time); + } + + public void set_active_slice(SliceRenderer? active_slice) { + if (active_slice == this) { + this.fade.reset_target(1.0, Config.global.theme.transition_time); + } else { + this.fade.reset_target(0.0, Config.global.theme.transition_time); + } + } + + public void draw(double frame_time, Cairo.Context ctx, double angle, double distance) { + + double direction = 2.0 * PI * position/parent.slice_count() + this.fade_rotation.val; + double max_scale = 1.0/Config.global.theme.max_zoom; + double diff = fabs(angle-direction); + + if (diff > PI) + diff = 2 * PI - diff; + + if (diff < 2 * PI * Config.global.theme.zoom_range) + max_scale = (Config.global.theme.max_zoom/(diff * (Config.global.theme.max_zoom - 1) + /(2 * PI * Config.global.theme.zoom_range) + 1)) + /Config.global.theme.max_zoom; + + active = ((parent.active_slice >= 0) && (diff < PI/parent.slice_count())); + + max_scale = (parent.active_slice >= 0 ? max_scale : 1.0/Config.global.theme.max_zoom); + + if (fabs(this.scale.end - max_scale) > Config.global.theme.max_zoom*0.005) + this.scale.reset_target(max_scale, Config.global.theme.transition_time); + + this.scale.update(frame_time); + this.alpha.update(frame_time); + this.fade.update(frame_time); + this.fade_scale.update(frame_time); + this.fade_rotation.update(frame_time); + + ctx.save(); + + double radius = Config.global.theme.radius; + + if (atan((Config.global.theme.slice_radius+Config.global.theme.slice_gap) + /(radius/Config.global.theme.max_zoom)) > PI/parent.slice_count()) { + radius = (Config.global.theme.slice_radius+Config.global.theme.slice_gap) + /tan(PI/parent.slice_count())*Config.global.theme.max_zoom; + } + + ctx.scale(scale.val*fade_scale.val, scale.val*fade_scale.val); + ctx.translate(cos(direction)*radius, sin(direction)*radius); + + ctx.push_group(); + + ctx.set_operator(Cairo.Operator.ADD); + + if (fade.val > 0.0) active_icon.paint_on(ctx, this.alpha.val*this.fade.val); + if (fade.val < 1.0) inactive_icon.paint_on(ctx, this.alpha.val*(1.0 - fade.val)); + + if (this.parent.show_hotkeys) { + ctx.set_operator(Cairo.Operator.ATOP); + ctx.set_source_rgba(0, 0, 0, 0.5); + ctx.paint(); + } + + ctx.set_operator(Cairo.Operator.OVER); + + + ctx.pop_group_to_source(); + ctx.paint(); + + if (this.parent.show_hotkeys) + this.hotkey.paint_on(ctx, 1.0); + + ctx.restore(); + } +} + +} diff --git a/src/themes/centerLayer.vala b/src/themes/centerLayer.vala new file mode 100644 index 0000000..3469fd0 --- /dev/null +++ b/src/themes/centerLayer.vala @@ -0,0 +1,111 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// This class representing a layer of the center of a pie. Each theme +/// may have plenty of them. +///////////////////////////////////////////////////////////////////////// + +public class CenterLayer : GLib.Object { + + ///////////////////////////////////////////////////////////////////// + /// Possible rotation modes. + /// AUTO: Turns the layer continously. + /// TO_MOUSE: Turns the layer always to the pointer. + /// TO_ACTIVE: Turns the layer to the active slice. + ///////////////////////////////////////////////////////////////////// + + public enum RotationMode {AUTO, TO_MOUSE, TO_ACTIVE} + + ///////////////////////////////////////////////////////////////////// + /// Information on the contained image. + ///////////////////////////////////////////////////////////////////// + + public Image image {get; private set;} + public string image_file; + + ///////////////////////////////////////////////////////////////////// + /// Properties for the active state of this layer. + ///////////////////////////////////////////////////////////////////// + + public double active_scale {get; private set;} + public double active_rotation_speed {get; private set;} + public double active_alpha {get; private set;} + public bool active_colorize {get; private set;} + public RotationMode active_rotation_mode {get; private set;} + + ///////////////////////////////////////////////////////////////////// + /// Properties for the inactive state of this layer. + ///////////////////////////////////////////////////////////////////// + + public double inactive_scale {get; private set;} + public double inactive_rotation_speed {get; private set;} + public double inactive_alpha {get; private set;} + public bool inactive_colorize {get; private set;} + public RotationMode inactive_rotation_mode {get; private set;} + + ///////////////////////////////////////////////////////////////////// + /// The current rotation of this layer. TODO: Remove this. + ///////////////////////////////////////////////////////////////////// + + public double rotation {get; set;} + + ///////////////////////////////////////////////////////////////////// + /// Helper variable for image loading. + ///////////////////////////////////////////////////////////////////// + + private int center_radius; + + ///////////////////////////////////////////////////////////////////// + /// C'tor, initializes all members of the layer. + ///////////////////////////////////////////////////////////////////// + + public CenterLayer(string image_file, int center_radius, double active_scale, double active_rotation_speed, + double active_alpha, bool active_colorize, RotationMode active_rotation_mode, + double inactive_scale, double inactive_rotation_speed, + double inactive_alpha, bool inactive_colorize, RotationMode inactive_rotation_mode) { + + this.image_file = image_file; + this.center_radius = center_radius; + + this.active_scale = active_scale; + this.active_rotation_speed = active_rotation_speed; + this.active_alpha = active_alpha; + this.active_colorize = active_colorize; + this.active_rotation_mode = active_rotation_mode; + + this.inactive_scale = inactive_scale; + this.inactive_rotation_speed = inactive_rotation_speed; + this.inactive_alpha = inactive_alpha; + this.inactive_colorize = inactive_colorize; + this.inactive_rotation_mode = inactive_rotation_mode; + + this.rotation = 0.0; + } + + ///////////////////////////////////////////////////////////////////// + /// Loads the contained image. + ///////////////////////////////////////////////////////////////////// + + public void load_image() { + this.image = new Image.from_file_at_size(image_file, 2*center_radius, 2*center_radius); + } +} + +} diff --git a/src/themes/sliceLayer.vala b/src/themes/sliceLayer.vala new file mode 100644 index 0000000..2620912 --- /dev/null +++ b/src/themes/sliceLayer.vala @@ -0,0 +1,65 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// This class representing a layer of a slice of a pie. Each theme may +/// have plenty of them. +///////////////////////////////////////////////////////////////////////// + +public class SliceLayer : GLib.Object { + + ///////////////////////////////////////////////////////////////////// + /// Information on the contained image. + ///////////////////////////////////////////////////////////////////// + + public Image image {get; set;} + public string icon_file {get; private set;} + + ///////////////////////////////////////////////////////////////////// + /// Properties of this layer. + ///////////////////////////////////////////////////////////////////// + + public bool colorize {get; private set; } + public bool is_icon {get; private set;} + public int icon_size {get; private set;} + + ///////////////////////////////////////////////////////////////////// + /// C'tor, initializes all members of the layer. + ///////////////////////////////////////////////////////////////////// + + public SliceLayer(string icon_file, int icon_size, bool colorize, bool is_icon) { + this.icon_file = icon_file; + this.colorize = colorize; + this.is_icon = is_icon; + this.icon_size = icon_size; + } + + ///////////////////////////////////////////////////////////////////// + /// Loads the contained image. + ///////////////////////////////////////////////////////////////////// + + public void load_image() { + if (this.icon_file == "" && this.is_icon == true) + this.image = new Image.empty(this.icon_size, this.icon_size, new Color.from_rgb(1, 1, 1)); + else + this.image = new Image.from_file_at_size(this.icon_file, this.icon_size, this.icon_size); + } +} + +} diff --git a/src/themes/theme.vala b/src/themes/theme.vala new file mode 100644 index 0000000..fa6f55a --- /dev/null +++ b/src/themes/theme.vala @@ -0,0 +1,489 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +using GLib.Math; + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A theme of Gnome-Pie. Can be loaded from XML-Files. +///////////////////////////////////////////////////////////////////////// + +public class Theme : GLib.Object { + + ///////////////////////////////////////////////////////////////////// + /// Properties of a theme. + ///////////////////////////////////////////////////////////////////// + + public string directory {get; private set; default="";} + public string name {get; private set; default="";} + public string description {get; private set; default="";} + public string author {get; private set; default="";} + public string email {get; private set; default="";} + public double radius {get; private set; default=150;} + public double max_zoom {get; private set; default=1.2;} + public double zoom_range {get; private set; default=0.2;} + public double transition_time {get; private set; default=0.5;} + public double fade_in_time {get; private set; default=0.2;} + public double fade_out_time {get; private set; default=0.1;} + public double fade_in_zoom {get; private set; default=1.0;} + public double fade_out_zoom {get; private set; default=1.0;} + public double fade_in_rotation {get; private set; default=0.0;} + public double fade_out_rotation{get; private set; default=0.0;} + public double springiness {get; private set; default=0.0;} + public double center_radius {get; private set; default=90.0;} + public double active_radius {get; private set; default=45.0;} + public double slice_radius {get; private set; default=32.0;} + public double slice_gap {get; private set; default=14.0;} + public bool caption {get; private set; default=false;} + public string caption_font {get; private set; default="sans 12";} + public int caption_width {get; private set; default=100;} + public int caption_height {get; private set; default=100;} + public double caption_position {get; private set; default=0.0;} + public Color caption_color {get; private set; default=new Color();} + + public Gee.ArrayList center_layers {get; private set;} + public Gee.ArrayList active_slice_layers {get; private set;} + public Gee.ArrayList inactive_slice_layers {get; private set;} + + ///////////////////////////////////////////////////////////////////// + /// C'tor, creates a theme object for a given theme directory. This + /// directory should contain a theme.xml file. + ///////////////////////////////////////////////////////////////////// + + public Theme(string dir) { + this.center_layers = new Gee.ArrayList(); + this.active_slice_layers = new Gee.ArrayList(); + this.inactive_slice_layers = new Gee.ArrayList(); + + this.directory = dir; + + this.load(); + } + + ///////////////////////////////////////////////////////////////////// + /// Loads the theme from its directory. Images have to be loaded + /// explicitly. + ///////////////////////////////////////////////////////////////////// + + public void load() { + this.center_layers.clear(); + this.active_slice_layers.clear(); + this.inactive_slice_layers.clear(); + + Xml.Parser.init(); + string path = this.directory + "/theme.xml"; + + Xml.Doc* themeXML = Xml.Parser.parse_file(path); + if (themeXML == null) { + warning("Error parsing theme: \"" + path + "\" not found!"); + return; + } + + Xml.Node* root = themeXML->get_root_element(); + if (root == null) { + delete themeXML; + warning("Invalid theme \"" + this.directory + "\": theme.xml is empty!"); + return; + } + + this.parse_root(root); + + delete themeXML; + Xml.Parser.cleanup(); + + this.radius *= max_zoom; + } + + ///////////////////////////////////////////////////////////////////// + /// Loads all images of the theme. + ///////////////////////////////////////////////////////////////////// + + public void load_images() { + foreach (var layer in this.center_layers) + layer.load_image(); + foreach (var layer in this.active_slice_layers) + layer.load_image(); + foreach (var layer in this.inactive_slice_layers) + layer.load_image(); + } + + ///////////////////////////////////////////////////////////////////// + /// The following methods parse specific parts of the theme file. + /// Nothing special here, just some boring code. + ///////////////////////////////////////////////////////////////////// + + private void parse_root(Xml.Node* root) { + for (Xml.Attr* attribute = root->properties; attribute != null; attribute = attribute->next) { + string attr_name = attribute->name.down(); + string attr_content = attribute->children->content; + + switch (attr_name) { + case "name": + name = attr_content; + break; + case "description": + description = attr_content; + break; + case "email": + email = attr_content; + break; + case "author": + author = attr_content; + break; + default: + warning("Invalid attribute \"" + attr_name + "\" in element!"); + break; + } + } + for (Xml.Node* node = root->children; node != null; node = node->next) { + if (node->type == Xml.ElementType.ELEMENT_NODE) { + parse_pie(node); + } + } + } + + ///////////////////////////////////////////////////////////////////// + /// Parses a element from the theme.xml file. + ///////////////////////////////////////////////////////////////////// + + private void parse_pie(Xml.Node* pie) { + for (Xml.Attr* attribute = pie->properties; attribute != null; attribute = attribute->next) { + string attr_name = attribute->name.down(); + string attr_content = attribute->children->content; + + switch (attr_name) { + case "radius": + radius = double.parse(attr_content) * Config.global.global_scale; + break; + case "maxzoom": + max_zoom = double.parse(attr_content); + break; + case "zoomrange": + zoom_range = double.parse(attr_content); + break; + case "transitiontime": + transition_time = double.parse(attr_content); + break; + case "fadeintime": + fade_in_time = double.parse(attr_content); + break; + case "fadeouttime": + fade_out_time = double.parse(attr_content); + break; + case "fadeinzoom": + fade_in_zoom = double.parse(attr_content); + break; + case "fadeoutzoom": + fade_out_zoom = double.parse(attr_content); + break; + case "fadeinrotation": + fade_in_rotation = double.parse(attr_content); + break; + case "fadeoutrotation": + fade_out_rotation = double.parse(attr_content); + break; + case "springiness": + springiness = double.parse(attr_content); + break; + default: + warning("Invalid attribute \"" + attr_name + "\" in element!"); + break; + } + } + for (Xml.Node* node = pie->children; node != null; node = node->next) { + if (node->type == Xml.ElementType.ELEMENT_NODE) { + string element_name = node->name.down(); + switch (element_name) { + case "center": + parse_center(node); + break; + case "slices": + parse_slices(node); + break; + case "caption": + caption = true; + parse_caption(node); + break; + default: + warning("Invalid child element \"" + element_name + "\" in element!"); + break; + } + } + } + } + + ///////////////////////////////////////////////////////////////////// + /// Parses a
element from the theme.xml file. + ///////////////////////////////////////////////////////////////////// + + private void parse_center(Xml.Node* center) { + for (Xml.Attr* attribute = center->properties; attribute != null; attribute = attribute->next) { + string attr_name = attribute->name.down(); + string attr_content = attribute->children->content; + + switch (attr_name) { + case "radius": + center_radius = double.parse(attr_content) * Config.global.global_scale; + break; + case "activeradius": + active_radius = double.parse(attr_content) * Config.global.global_scale; + break; + default: + warning("Invalid attribute \"" + attr_name + "\" in
element!"); + break; + } + } + for (Xml.Node* node = center->children; node != null; node = node->next) { + if (node->type == Xml.ElementType.ELEMENT_NODE) { + string element_name = node->name.down(); + + if (element_name == "center_layer") { + parse_center_layer(node); + } else { + warning("Invalid child element \"" + element_name + "\" in
element!"); + } + } + } + } + + ///////////////////////////////////////////////////////////////////// + /// Parses a element from the theme.xml file. + ///////////////////////////////////////////////////////////////////// + + private void parse_slices(Xml.Node* slices) { + for (Xml.Attr* attribute = slices->properties; attribute != null; attribute = attribute->next) { + string attr_name = attribute->name.down(); + string attr_content = attribute->children->content; + + switch (attr_name) { + case "radius": + slice_radius = double.parse(attr_content) * Config.global.global_scale; + break; + case "mingap": + slice_gap = double.parse(attr_content) * Config.global.global_scale; + break; + default: + warning("Invalid attribute \"" + attr_name + "\" in element!"); + break; + } + } + for (Xml.Node* node = slices->children; node != null; node = node->next) { + if (node->type == Xml.ElementType.ELEMENT_NODE) { + string element_name = node->name.down(); + + if (element_name == "activeslice" || element_name == "inactiveslice") { + parse_slice_layers(node); + } else { + warning("Invalid child element \"" + element_name + "\" in element!"); + } + } + } + } + + ///////////////////////////////////////////////////////////////////// + /// Parses a element from the theme.xml file. + ///////////////////////////////////////////////////////////////////// + + private void parse_center_layer(Xml.Node* layer) { + + string file = ""; + double active_rotation_speed = 0.0; + double inactive_rotation_speed = 0.0; + double active_scale = 1.0; + double inactive_scale = 1.0; + double active_alpha = 1.0; + double inactive_alpha = 1.0; + bool active_colorize = false; + bool inactive_colorize = false; + CenterLayer.RotationMode active_rotation_mode = CenterLayer.RotationMode.AUTO; + CenterLayer.RotationMode inactive_rotation_mode = CenterLayer.RotationMode.AUTO; + + for (Xml.Attr* attribute = layer->properties; attribute != null; attribute = attribute->next) { + string attr_name = attribute->name.down(); + string attr_content = attribute->children->content; + + switch (attr_name) { + case "file": + file = attr_content; + break; + case "active_scale": + active_scale = double.parse(attr_content); + break; + case "active_alpha": + active_alpha = double.parse(attr_content); + break; + case "active_rotationmode": + switch (attr_content.down()) { + case "auto": + active_rotation_mode = CenterLayer.RotationMode.AUTO; + break; + case "turn_to_active": + active_rotation_mode = CenterLayer.RotationMode.TO_ACTIVE; + break; + case "turn_to_mouse": + active_rotation_mode = CenterLayer.RotationMode.TO_MOUSE; + break; + default: + warning("Invalid value \"" + attr_content + "\" for attribute \"" + attr_name + "\" in element!"); + break; + } + break; + case "active_rotationspeed": + active_rotation_speed = double.parse(attr_content); + break; + case "active_colorize": + active_colorize = bool.parse(attr_content); + break; + case "inactive_scale": + inactive_scale = double.parse(attr_content); + break; + case "inactive_alpha": + inactive_alpha = double.parse(attr_content); + break; + case "inactive_rotationmode": + switch (attr_content.down()) { + case "auto": + inactive_rotation_mode = CenterLayer.RotationMode.AUTO; + break; + case "turn_to_active": + inactive_rotation_mode = CenterLayer.RotationMode.TO_ACTIVE; + break; + case "turn_to_mouse": + inactive_rotation_mode = CenterLayer.RotationMode.TO_MOUSE; + break; + default: + warning("Invalid value \"" + attr_content + "\" for attribute \"" + attr_name + "\" in element!"); + break; + } + break; + case "inactive_rotationspeed": + inactive_rotation_speed = double.parse(attr_content); + break; + case "inactive_colorize": + inactive_colorize = bool.parse(attr_content); + break; + default: + warning("Invalid attribute \"" + attr_name + "\" in element!"); + break; + } + } + + double max_scale = GLib.Math.fmax(active_scale, inactive_scale); + center_layers.add(new CenterLayer(directory + "/" + file, (int)(center_radius*max_scale), active_scale/max_scale, active_rotation_speed, active_alpha, active_colorize, active_rotation_mode, + inactive_scale/max_scale, inactive_rotation_speed, inactive_alpha, inactive_colorize, inactive_rotation_mode)); + } + + ///////////////////////////////////////////////////////////////////// + /// Parses a element from the theme.xml file. + ///////////////////////////////////////////////////////////////////// + + private void parse_slice_layers(Xml.Node* slice) { + for (Xml.Node* layer = slice->children; layer != null; layer = layer->next) { + if (layer->type == Xml.ElementType.ELEMENT_NODE) { + string element_name = layer->name.down(); + + if (element_name == "slice_layer") { + string file = ""; + double scale = 1.0; + bool is_icon = false; + bool colorize = false; + + for (Xml.Attr* attribute = layer->properties; attribute != null; attribute = attribute->next) { + string attr_name = attribute->name.down(); + string attr_content = attribute->children->content; + + switch (attr_name) { + case "file": + file = attr_content; + break; + case "scale": + scale = double.parse(attr_content); + break; + case "type": + if (attr_content == "icon") + is_icon = true; + else if (attr_content != "file") + warning("Invalid attribute content " + attr_content + " for attribute " + attr_name + " in element!"); + break; + case "colorize": + colorize = bool.parse(attr_content); + break; + default: + warning("Invalid attribute \"" + attr_name + "\" in element!"); + break; + } + } + + if (file != "") + file = directory + "/" + file; + + int size = 2*(int)(slice_radius*scale*max_zoom); + + if (slice->name.down() == "activeslice") { + active_slice_layers.add(new SliceLayer(file, size, colorize, is_icon)); + } else { + inactive_slice_layers.add(new SliceLayer(file, size, colorize, is_icon)); + } + + } else { + warning("Invalid child element \"" + element_name + "\" in <" + slice->name + "> element!"); + } + } + } + } + + ///////////////////////////////////////////////////////////////////// + /// Parses a element from the theme.xml file. + ///////////////////////////////////////////////////////////////////// + + private void parse_caption(Xml.Node* caption) { + for (Xml.Attr* attribute = caption->properties; attribute != null; attribute = attribute->next) { + string attr_name = attribute->name.down(); + string attr_content = attribute->children->content; + + switch (attr_name) { + case "font": + caption_font = attr_content; + break; + case "width": + caption_width = (int)(int.parse(attr_content) * Config.global.global_scale); + if (caption_width % 2 == 1) + --caption_width; + break; + case "height": + caption_height = (int)(int.parse(attr_content) * Config.global.global_scale); + if (caption_height % 2 == 1) + --caption_height; + break; + case "position": + caption_position = double.parse(attr_content) * Config.global.global_scale; + break; + case "color": + caption_color = new Color.from_string(attr_content); + break; + default: + warning("Invalid attribute \"" + attr_name + "\" in element!"); + break; + } + } + + } + +} + +} diff --git a/src/utilities/animatedValue.vala b/src/utilities/animatedValue.vala new file mode 100644 index 0000000..32ab889 --- /dev/null +++ b/src/utilities/animatedValue.vala @@ -0,0 +1,190 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A class which interpolates smoothly between to given values. +/// Duration and interpolation mode can be specified. +///////////////////////////////////////////////////////////////////////// + +public class AnimatedValue : GLib.Object { + + ///////////////////////////////////////////////////////////////////// + /// The direction of the interpolation. + ///////////////////////////////////////////////////////////////////// + + public enum Direction { IN, OUT, IN_OUT, OUT_IN } + + ///////////////////////////////////////////////////////////////////// + /// Type of the interpolation, linear or cubic. + ///////////////////////////////////////////////////////////////////// + + private enum Type { LINEAR, CUBIC } + + ///////////////////////////////////////////////////////////////////// + /// Current value, interpolated. + ///////////////////////////////////////////////////////////////////// + + public double val { get; private set; } + + ///////////////////////////////////////////////////////////////////// + /// Starting value of the interpolation. + ///////////////////////////////////////////////////////////////////// + + public double start { get; private set; default=0.0; } + + ///////////////////////////////////////////////////////////////////// + /// Final value of the interpolation. + ///////////////////////////////////////////////////////////////////// + + public double end { get; private set; default=0.0; } + + ///////////////////////////////////////////////////////////////////// + /// The current state. In range 0 .. 1 + ///////////////////////////////////////////////////////////////////// + + private double state = 0.0; + + ///////////////////////////////////////////////////////////////////// + /// Duration of the interpolation. Should be in the same unit as + /// taken for the update() method. + ///////////////////////////////////////////////////////////////////// + + private double duration = 0.0; + + ///////////////////////////////////////////////////////////////////// + /// The amount of over-shooting of the cubicly interpolated value. + ///////////////////////////////////////////////////////////////////// + + private double multiplier = 0.0; + + ///////////////////////////////////////////////////////////////////// + /// Type of the interpolation, linear or cubic. + ///////////////////////////////////////////////////////////////////// + + private Type type = Type.LINEAR; + + ///////////////////////////////////////////////////////////////////// + /// The direction of the interpolation. + ///////////////////////////////////////////////////////////////////// + + private Direction direction = Direction.IN; + + ///////////////////////////////////////////////////////////////////// + /// Creates a new linearly interpolated value. + ///////////////////////////////////////////////////////////////////// + + public AnimatedValue.linear(double start, double end, double duration) { + this.val = start; + this.start = start; + this.end = end; + this.duration = duration; + } + + ///////////////////////////////////////////////////////////////////// + /// Creates a new cubicly interpolated value. + ///////////////////////////////////////////////////////////////////// + + public AnimatedValue.cubic(Direction direction, double start, double end, double duration, double multiplier = 0) { + this.val = start; + this.start = start; + this.end = end; + this.duration = duration; + this.direction = direction; + this.type = Type.CUBIC; + this.multiplier = multiplier; + } + + ///////////////////////////////////////////////////////////////////// + /// Resets the final value of the interpolation to a new value. The + /// current state is taken for the beginning from now. + ///////////////////////////////////////////////////////////////////// + + public void reset_target(double end, double duration) { + this.start = this.val; + this.end = end; + this.duration = duration; + this.state = 0.0; + } + + ///////////////////////////////////////////////////////////////////// + /// Updates the interpolated value according to it's type. + ///////////////////////////////////////////////////////////////////// + + public void update(double time) { + this.state += time/this.duration; + + if (state < 1) { + + switch (this.type) { + case Type.LINEAR: + this.val = update_linear(); + break; + case Type.CUBIC: + switch (this.direction) { + case Direction.IN: + this.val = update_ease_in(); + return; + case Direction.OUT: + this.val = update_ease_out(); + return; + case Direction.IN_OUT: + this.val = update_ease_in_out(); + return; + case Direction.OUT_IN: + this.val = update_ease_out_in(); + return; + } + break; + } + } else if (this.val != this.end) { + this.val = this.end; + } + } + + ///////////////////////////////////////////////////////////////////// + /// The following equations are based on Robert Penner's easing + /// equations. See (http://www.robertpenner.com/easing/) and their + /// adaption by Zeh Fernando, Nate Chatellier and Arthur Debert for + /// the Tweener class. See (http://code.google.com/p/tweener/). + ///////////////////////////////////////////////////////////////////// + + private double update_linear(double t = this.state, double s = this.start, double e = this.end) { + return (s + t*(e - s)); + } + + private double update_ease_in(double t = this.state, double s = this.start, double e = this.end) { + return (s + (t*t*((multiplier+1)*t-multiplier))*(e - s)); + } + + private double update_ease_out(double t = this.state, double s = this.start, double e = this.end) { + return (s + ((t-1) * (t-1) * ((multiplier+1)*(t-1)+multiplier) + 1) * (e - s)); + } + + private double update_ease_in_out(double t = this.state, double s = this.start, double e = this.end) { + if (this.state < 0.5) return update_ease_in(t*2, s, e - (e-s)*0.5); + else return update_ease_out(t*2-1, s + (e-s)*0.5, e); + } + + private double update_ease_out_in(double t = this.state, double s = this.start, double e = this.end) { + if (this.state < 0.5) return update_ease_out(t*2, s, e - (e-s)*0.5); + else return update_ease_in(t*2-1, s + (e-s)*0.5, e); + } +} + +} diff --git a/src/utilities/bindingManager.vala b/src/utilities/bindingManager.vala new file mode 100644 index 0000000..8795124 --- /dev/null +++ b/src/utilities/bindingManager.vala @@ -0,0 +1,196 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// Globally binds key stroke to given ID's. When one of the bound +/// strokes is invoked, a signal with the according ID is emitted. +///////////////////////////////////////////////////////////////////////// + +public class BindingManager : GLib.Object { + + ///////////////////////////////////////////////////////////////////// + /// Called when a stored binding is invoked. The according ID is + /// passed as argument. + ///////////////////////////////////////////////////////////////////// + + public signal void on_press(string id); + + ///////////////////////////////////////////////////////////////////// + /// A list storing bindings, which are invoked even if Gnome-Pie + /// doesn't have the current focus + ///////////////////////////////////////////////////////////////////// + + private Gee.List bindings = new Gee.ArrayList(); + + ///////////////////////////////////////////////////////////////////// + /// Ignored modifier masks, used to grab all keys even if these locks + /// are active. + ///////////////////////////////////////////////////////////////////// + + private static uint[] lock_modifiers = { + 0, + Gdk.ModifierType.MOD2_MASK, + Gdk.ModifierType.LOCK_MASK, + Gdk.ModifierType.MOD5_MASK, + Gdk.ModifierType.MOD2_MASK|Gdk.ModifierType.LOCK_MASK, + Gdk.ModifierType.MOD2_MASK|Gdk.ModifierType.MOD5_MASK, + Gdk.ModifierType.LOCK_MASK|Gdk.ModifierType.MOD5_MASK, + Gdk.ModifierType.MOD2_MASK|Gdk.ModifierType.LOCK_MASK|Gdk.ModifierType.MOD5_MASK + }; + + ///////////////////////////////////////////////////////////////////// + /// Helper class to store keybinding + ///////////////////////////////////////////////////////////////////// + + private class Keybinding { + + public Keybinding(string accelerator, int keycode, Gdk.ModifierType modifiers, string id) { + this.accelerator = accelerator; + this.keycode = keycode; + this.modifiers = modifiers; + this.id = id; + } + + public string accelerator { get; set; } + public int keycode { get; set; } + public Gdk.ModifierType modifiers { get; set; } + public string id { get; set; } + } + + ///////////////////////////////////////////////////////////////////// + /// C'tor adds the event filter to the root window. + ///////////////////////////////////////////////////////////////////// + + public BindingManager() { + // init filter to retrieve X.Events + Gdk.Window rootwin = Gdk.get_default_root_window(); + if(rootwin != null) { + rootwin.add_filter(event_filter); + } + } + + ///////////////////////////////////////////////////////////////////// + /// Binds the ID to the given accelerator. + ///////////////////////////////////////////////////////////////////// + + public void bind(string accelerator, string id) { + uint keysym; + Gdk.ModifierType modifiers; + Gtk.accelerator_parse(accelerator, out keysym, out modifiers); + + if (keysym == 0) { + warning("Invalid keystroke: " + accelerator); + return; + } + + Gdk.Window rootwin = Gdk.get_default_root_window(); + X.Display display = Gdk.x11_drawable_get_xdisplay(rootwin); + X.ID xid = Gdk.x11_drawable_get_xid(rootwin); + int keycode = display.keysym_to_keycode(keysym); + + if(keycode != 0) { + Gdk.error_trap_push(); + + foreach(uint lock_modifier in lock_modifiers) { + display.grab_key(keycode, modifiers|lock_modifier, xid, false, X.GrabMode.Async, X.GrabMode.Async); + } + + Gdk.flush(); + + Keybinding binding = new Keybinding(accelerator, keycode, modifiers, id); + bindings.add(binding); + } + } + + ///////////////////////////////////////////////////////////////////// + /// Unbinds the accelerator of the given ID. + ///////////////////////////////////////////////////////////////////// + + public void unbind(string id) { + Gdk.Window rootwin = Gdk.get_default_root_window(); + X.Display display = Gdk.x11_drawable_get_xdisplay(rootwin); + X.ID xid = Gdk.x11_drawable_get_xid(rootwin); + Gee.List remove_bindings = new Gee.ArrayList(); + foreach(var binding in bindings) { + if(id == binding.id) { + foreach(uint lock_modifier in lock_modifiers) { + display.ungrab_key(binding.keycode, binding.modifiers, xid); + } + remove_bindings.add(binding); + } + } + + bindings.remove_all(remove_bindings); + } + + ///////////////////////////////////////////////////////////////////// + /// Returns a human readable accelerator for the given ID. + ///////////////////////////////////////////////////////////////////// + + public string get_accelerator_label_of(string id) { + string accelerator = this.get_accelerator_of(id); + + if (accelerator == "") + return _("Not bound"); + + uint key = 0; + Gdk.ModifierType mods; + Gtk.accelerator_parse(accelerator, out key, out mods); + return Gtk.accelerator_get_label(key, mods); + } + + ///////////////////////////////////////////////////////////////////// + /// Returns the accelerator to which the given ID is bound. + ///////////////////////////////////////////////////////////////////// + + public string get_accelerator_of(string id) { + foreach (var binding in bindings) { + if (binding.id == id) { + return binding.accelerator; + } + } + + return ""; + } + + ///////////////////////////////////////////////////////////////////// + /// Event filter method needed to fetch X.Events + ///////////////////////////////////////////////////////////////////// + + private Gdk.FilterReturn event_filter(Gdk.XEvent gdk_xevent, Gdk.Event gdk_event) { + Gdk.FilterReturn filter_return = Gdk.FilterReturn.CONTINUE; + + void* pointer = &gdk_xevent; + X.Event* xevent = (X.Event*) pointer; + + if(xevent->type == X.EventType.KeyPress) { + foreach(var binding in bindings) { + // remove NumLock, CapsLock and ScrollLock from key state + uint event_mods = xevent.xkey.state & ~ (lock_modifiers[7]); + if(xevent->xkey.keycode == binding.keycode && event_mods == binding.modifiers) { + on_press(binding.id); + } + } + } + + return filter_return; + } +} + +} diff --git a/src/utilities/color.vala b/src/utilities/color.vala new file mode 100644 index 0000000..836411e --- /dev/null +++ b/src/utilities/color.vala @@ -0,0 +1,305 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +using GLib.Math; + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A Color class with full rgb/hsv support +/// and some useful utility methods. +///////////////////////////////////////////////////////////////////////// + +public class Color: GLib.Object { + + ///////////////////////////////////////////////////////////////////// + /// Private members, storing the actual color information. + /// In range 0 .. 1 + ///////////////////////////////////////////////////////////////////// + + private float _r; + private float _g; + private float _b; + private float _a; + + ///////////////////////////////////////////////////////////////////// + /// Creates a white Color. + ///////////////////////////////////////////////////////////////////// + + public Color() { + Color.from_rgb(1.0f, 1.0f, 1.0f); + } + + ///////////////////////////////////////////////////////////////////// + /// Creates a solid color with the given RGB values. + ///////////////////////////////////////////////////////////////////// + + public Color.from_rgb(float red, float green, float blue) { + Color.from_rgba(red, green, blue, 1.0f); + } + + ///////////////////////////////////////////////////////////////////// + /// Creates a translucient color with the given RGBA values. + ///////////////////////////////////////////////////////////////////// + + public Color.from_rgba(float red, float green, float blue, float alpha) { + r = red; + g = green; + b = blue; + a = alpha; + } + + ///////////////////////////////////////////////////////////////////// + /// Creates a color from the given Gdk.Color + ///////////////////////////////////////////////////////////////////// + + public Color.from_gdk(Gdk.Color color) { + Color.from_rgb( + (float)color.red/65535.0f, + (float)color.green/65535.0f, + (float)color.blue/65535.0f + ); + } + + ///////////////////////////////////////////////////////////////////// + /// Creates a color, parsed from a string, such as #22EE33 + ///////////////////////////////////////////////////////////////////// + + public Color.from_string(string hex_string) { + Gdk.Color color; + Gdk.Color.parse(hex_string, out color); + Color.from_gdk(color); + } + + ///////////////////////////////////////////////////////////////////// + /// Gets the main color from an Image. Code from Unity. + ///////////////////////////////////////////////////////////////////// + + public Color.from_icon(Image icon) { + unowned uchar[] data = icon.surface.get_data(); + + uint width = icon.surface.get_width(); + uint height = icon.surface.get_height(); + uint row_bytes = icon.surface.get_stride(); + + double total = 0.0; + double rtotal = 0.0; + double gtotal = 0.0; + double btotal = 0.0; + + for (uint i = 0; i < width; ++i) { + for (uint j = 0; j < height; ++j) { + uint pixel = j * row_bytes + i * 4; + double b = data[pixel + 0]/255.0; + double g = data[pixel + 1]/255.0; + double r = data[pixel + 2]/255.0; + double a = data[pixel + 3]/255.0; + + double saturation = (fmax (r, fmax (g, b)) - fmin (r, fmin (g, b))); + double relevance = 0.1 + 0.9 * a * saturation; + + rtotal += (r * relevance); + gtotal += (g * relevance); + btotal += (b * relevance); + + total += relevance; + } + } + + Color.from_rgb((float)(rtotal/total), (float)(gtotal/total), (float)(btotal/total)); + + if (s > 0.15f) s = 0.65f; + + v = 1.0f; + } + + ///////////////////////////////////////////////////////////////////// + /// The reddish part of the color. + ///////////////////////////////////////////////////////////////////// + + public float r { + get { + return _r; + } + set { + if (value > 1.0f) _r = 1.0f; + else if (value < 0.0f) _r = 0.0f; + else _r = value; + } + } + + ///////////////////////////////////////////////////////////////////// + /// The greenish part of the color. + ///////////////////////////////////////////////////////////////////// + + public float g { + get { + return _g; + } + set { + if (value > 1.0f) _g = 1.0f; + else if (value < 0.0f) _g = 0.0f; + else _g = value; + } + } + + ///////////////////////////////////////////////////////////////////// + /// The blueish part of the color. + ///////////////////////////////////////////////////////////////////// + + public float b { + get { + return _b; + } + set { + if (value > 1.0f) _b = 1.0f; + else if (value < 0.0f) _b = 0.0f; + else _b = value; + } + } + + ///////////////////////////////////////////////////////////////////// + /// The transparency of the color. + ///////////////////////////////////////////////////////////////////// + + public float a { + get { + return _a; + } + set { + if (value > 1.0f) _a = 1.0f; + else if (value < 0.0f) _a = 0.0f; + else _a = value; + } + } + + ///////////////////////////////////////////////////////////////////// + /// The hue of the color. + ///////////////////////////////////////////////////////////////////// + + public float h { + get { + if (s > 0.0f) { + float maxi = fmaxf(fmaxf(r, g), b); + float mini = fminf(fminf(r, g), b); + + if (maxi == r) + return fmodf(60.0f*((g-b)/(maxi-mini))+360.0f, 360.0f); + else if (maxi == g) + return fmodf(60.0f*(2.0f + (b-r)/(maxi-mini))+360.0f, 360.0f); + else + return fmodf(60.0f*(4.0f + (r-g)/(maxi-mini))+360.0f, 360.0f); + } + else return 0.0f; + } + set { + setHSV(value, s, v); + } + } + + ///////////////////////////////////////////////////////////////////// + /// The saturation of the color. + ///////////////////////////////////////////////////////////////////// + + public float s { + get { + if (v == 0.0f) return 0.0f; + else return ((v-fminf(fminf(r, g), b)) / v); + } + set { + if (value > 1.0f) setHSV(h, 1.0f, v); + else if (value < 0.0f) setHSV(h, 0.0f, v); + else setHSV(h, value, v); + } + } + + ///////////////////////////////////////////////////////////////////// + /// The value of the color. + ///////////////////////////////////////////////////////////////////// + + public float v { + get { + return fmaxf(fmaxf(r, g), b); + } + set { + if (value > 1) setHSV(h, s, 1.0f); + else if (value < 0) setHSV(h, s, 0.0f); + else setHSV(h, s, value); + } + } + + ///////////////////////////////////////////////////////////////////// + /// Inverts the color. + ///////////////////////////////////////////////////////////////////// + + public void invert() { + h += 180.0f; + v = 1.0f - v; + } + + ///////////////////////////////////////////////////////////////////// + /// Private member, used to apply color changes. + ///////////////////////////////////////////////////////////////////// + + private void setHSV(float hue, float saturation, float val) { + if(saturation == 0) { + r = val; + g = val; + b = val; + return; + } + hue = fmodf(hue, 360); + hue /= 60; + int i = (int) floorf(hue); + float f = hue - i; + + switch(i) { + case 0: + r = val; + g = val * (1.0f - saturation * (1.0f - f)); + b = val * (1.0f - saturation); + break; + case 1: + r = val * (1.0f - saturation * f); + g = val; + b = val * (1.0f - saturation); + break; + case 2: + r = val * (1.0f - saturation); + g = val; + b = val * (1.0f - saturation * (1.0f - f)); + break; + case 3: + r = val * (1.0f - saturation); + g = val * (1.0f - saturation * f); + b = val; + break; + case 4: + r = val * (1.0f - saturation * (1.0f - f)); + g = val * (1.0f - saturation); + b = val; + break; + default: + r = val; + g = val * (1.0f - saturation); + b = val * (1.0f - saturation * f); + break; + } + } +} + +} diff --git a/src/utilities/config.vala b/src/utilities/config.vala new file mode 100644 index 0000000..c5dedd5 --- /dev/null +++ b/src/utilities/config.vala @@ -0,0 +1,202 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A singleton class for storing global settings. These settings can +/// be loaded from and saved to an XML file. +///////////////////////////////////////////////////////////////////////// + +public class Config : GLib.Object { + + ///////////////////////////////////////////////////////////////////// + /// The singleton instance of this class. + ///////////////////////////////////////////////////////////////////// + + private static Config _instance = null; + + ///////////////////////////////////////////////////////////////////// + /// Returns the singleton instance. + ///////////////////////////////////////////////////////////////////// + + public static Config global { + get { + if (_instance == null) { + _instance = new Config(); + _instance.load(); + } + return _instance; + } + private set { + _instance = value; + } + } + + ///////////////////////////////////////////////////////////////////// + /// All settings variables. + ///////////////////////////////////////////////////////////////////// + + public Theme theme { get; set; } + public double refresh_rate { get; set; default = 60.0; } + public double global_scale { get; set; default = 1.0; } + public bool show_indicator { get; set; default = true; } + public bool open_at_mouse { get; set; default = true; } + public bool turbo_mode { get; set; default = false; } + public bool auto_start { get; set; default = false; } + public Gee.ArrayList themes { get; private set; } + + ///////////////////////////////////////////////////////////////////// + /// Saves all above variables to a file. + ///////////////////////////////////////////////////////////////////// + + public void save() { + var writer = new Xml.TextWriter.filename(Paths.settings); + writer.start_document("1.0"); + writer.start_element("settings"); + writer.write_attribute("theme", theme.name); + writer.write_attribute("refresh_rate", refresh_rate.to_string()); + writer.write_attribute("global_scale", global_scale.to_string()); + writer.write_attribute("show_indicator", show_indicator ? "true" : "false"); + writer.write_attribute("open_at_mouse", open_at_mouse ? "true" : "false"); + writer.write_attribute("turbo_mode", turbo_mode ? "true" : "false"); + writer.end_element(); + writer.end_document(); + } + + ///////////////////////////////////////////////////////////////////// + /// Loads all settings variables from a file. + ///////////////////////////////////////////////////////////////////// + + private void load() { + + // check for auto_start filename + this.auto_start = FileUtils.test(Paths.autostart, FileTest.EXISTS); + + // parse the settings file + Xml.Parser.init(); + Xml.Doc* settingsXML = Xml.Parser.parse_file(Paths.settings); + bool error_occrured = false; + string theme_name = ""; + + if (settingsXML != null) { + + Xml.Node* root = settingsXML->get_root_element(); + if (root != null) { + + for (Xml.Attr* attribute = root->properties; attribute != null; attribute = attribute->next) { + string attr_name = attribute->name.down(); + string attr_content = attribute->children->content; + + switch (attr_name) { + case "theme": + theme_name = attr_content; + break; + case "refresh_rate": + refresh_rate = double.parse(attr_content); + break; + case "global_scale": + global_scale = double.parse(attr_content); + global_scale.clamp(0.5, 2.0); + break; + case "show_indicator": + show_indicator = bool.parse(attr_content); + break; + case "open_at_mouse": + open_at_mouse = bool.parse(attr_content); + break; + case "turbo_mode": + turbo_mode = bool.parse(attr_content); + break; + default: + warning("Invalid setting \"" + attr_name + "\" in gnome-pie.conf!"); + break; + } + } + + Xml.Parser.cleanup(); + + } else { + warning("Error loading settings: gnome-pie.conf is empty! Using defaults..."); + error_occrured = true; + } + + delete settingsXML; + + } else { + warning("Error loading settings: gnome-pie.conf not found! Using defaults..."); + error_occrured = true; + } + + load_themes(theme_name); + + if (error_occrured) save(); + } + + ///////////////////////////////////////////////////////////////////// + /// Registers all themes in the user's and in the global + /// theme directory. + ///////////////////////////////////////////////////////////////////// + + public void load_themes(string current) { + themes = new Gee.ArrayList(); + try { + string name; + + // load global themes + var d = Dir.open(Paths.global_themes); + while ((name = d.read_name()) != null) { + var theme = new Theme(Paths.global_themes + "/" + name); + if (theme != null) + themes.add(theme); + } + + // load local themes + d = Dir.open(Paths.local_themes); + while ((name = d.read_name()) != null) { + var theme = new Theme(Paths.local_themes + "/" + name); + if (theme != null) + themes.add(theme); + } + + } catch (Error e) { + warning (e.message); + } + + if (themes.size > 0) { + if (current == "") { + current = "Unity"; + warning("No theme specified! Using default..."); + } + foreach (var t in themes) { + if (t.name == current) { + theme = t; + theme.load_images(); + break; + } + } + if (theme == null) { + theme = themes[0]; + warning("Theme \"" + current + "\" not found! Using fallback..."); + } + } + else error("No theme found!"); + } + +} + +} diff --git a/src/utilities/icon.vala b/src/utilities/icon.vala new file mode 100644 index 0000000..1c8a9f4 --- /dev/null +++ b/src/utilities/icon.vala @@ -0,0 +1,102 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A class representing a square-shaped icon, loaded from the users +/// icon theme. +///////////////////////////////////////////////////////////////////////// + +public class Icon : Image { + + ///////////////////////////////////////////////////////////////////// + /// A cache which stores loaded icon. It is cleared when the icon + /// theme of the user changes. The key is in form @. + ///////////////////////////////////////////////////////////////////// + + private static Gee.HashMap cache { private get; private set; } + + ///////////////////////////////////////////////////////////////////// + /// Initializes the cache. + ///////////////////////////////////////////////////////////////////// + + public static void init() { + clear_cache(); + + Gtk.IconTheme.get_default().changed.connect(() => { + clear_cache(); + }); + } + + ///////////////////////////////////////////////////////////////////// + /// Clears the cache. + ///////////////////////////////////////////////////////////////////// + + public static void clear_cache() { + cache = new Gee.HashMap(); + } + + ///////////////////////////////////////////////////////////////////// + /// Loads an icon from the current icon theme of the user. + ///////////////////////////////////////////////////////////////////// + + public Icon(string icon_name, int size) { + var cached = this.cache.get("%s@%u".printf(icon_name, size)); + + if (cached == null) { + this.load_file_at_size(this.get_icon_file(icon_name, size), size, size); + this.cache.set("%s@%u".printf(icon_name, size), this.surface); + } else { + this.surface = cached; + } + } + + ///////////////////////////////////////////////////////////////////// + /// Returns the size of the icon in pixels. Greetings to Liskov. + ///////////////////////////////////////////////////////////////////// + + public int size() { + return base.width(); + } + + ///////////////////////////////////////////////////////////////////// + /// Returns the filename for a given system icon. + ///////////////////////////////////////////////////////////////////// + + public static string get_icon_file(string icon_name, int size) { + string result = ""; + + var icon_theme = Gtk.IconTheme.get_default(); + var file = icon_theme.lookup_icon(icon_name, size, 0); + if (file != null) result = file.get_filename(); + + if (result == "") { + warning("Icon \"" + icon_name + "\" not found! Using default icon..."); + icon_name = "application-default-icon"; + file = icon_theme.lookup_icon(icon_name, size, 0); + if (file != null) result = file.get_filename(); + } + + if (result == "") + warning("Icon \"" + icon_name + "\" not found! Will be ugly..."); + + return result; + } +} + +} diff --git a/src/utilities/image.vala b/src/utilities/image.vala new file mode 100644 index 0000000..836e4e2 --- /dev/null +++ b/src/utilities/image.vala @@ -0,0 +1,163 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A class which loads image files. It can load image files in various +/// formats, including jpeg, png and svg. +///////////////////////////////////////////////////////////////////////// + +public class Image : GLib.Object { + + ///////////////////////////////////////////////////////////////////// + /// The internally used surface. + ///////////////////////////////////////////////////////////////////// + + public Cairo.ImageSurface surface { public get; protected set; default=null; } + + ///////////////////////////////////////////////////////////////////// + /// Creates an empty Image. + ///////////////////////////////////////////////////////////////////// + + public Image.empty(int width, int height, Color? color = null) { + this.surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, width, height); + + if (color != null) { + var ctx = this.context(); + ctx.set_source_rgb(color.r, color.g, color.b); + ctx.paint(); + } + } + + ///////////////////////////////////////////////////////////////////// + /// Creates an image from the the given filename. + ///////////////////////////////////////////////////////////////////// + + public Image.from_file(string filename) { + this.load_file(filename); + } + + ///////////////////////////////////////////////////////////////////// + /// Creates an image from the the given filename at a given size. + ///////////////////////////////////////////////////////////////////// + + public Image.from_file_at_size(string filename, int width, int height) { + this.load_file_at_size(filename, width, height); + } + + ///////////////////////////////////////////////////////////////////// + /// Creates an image from the the given Gdk.Pixbuf. + ///////////////////////////////////////////////////////////////////// + + public Image.from_pixbuf(Gdk.Pixbuf pixbuf) { + this.load_pixbuf(pixbuf); + } + + public Image.capture_screen(int posx, int posy, int width, int height) { + Gdk.Window root = Gdk.get_default_root_window(); + Gdk.Pixbuf pixbuf = Gdk.pixbuf_get_from_drawable(null, root, null, posx, posy, 0, 0, width, height); + + this.load_pixbuf(pixbuf); + } + + ///////////////////////////////////////////////////////////////////// + /// Loads an image from the the given filename. + ///////////////////////////////////////////////////////////////////// + + public void load_file(string filename) { + try { + var pixbuf = new Gdk.Pixbuf.from_file(filename); + + if (pixbuf != null) { + this.load_pixbuf(pixbuf); + } else { + warning("Failed to load " + filename + "!"); + } + } catch (GLib.Error e) { + message("Error loading image file: %s", e.message); + this.surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, 1, 1); + } + } + + ///////////////////////////////////////////////////////////////////// + /// Loads an image from the the given filename at a given size. + ///////////////////////////////////////////////////////////////////// + + public void load_file_at_size(string filename, int width, int height) { + try { + var pixbuf = new Gdk.Pixbuf.from_file_at_size(filename, width, height); + + if (pixbuf != null) { + this.load_pixbuf(pixbuf); + } else { + warning("Failed to load " + filename + "!"); + } + } catch (GLib.Error e) { + message("Error loading image file: %s", e.message); + this.surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, width, height); + } + } + + ///////////////////////////////////////////////////////////////////// + /// Loads an image from the the given Gdk.Pixbuf. + ///////////////////////////////////////////////////////////////////// + + public void load_pixbuf(Gdk.Pixbuf pixbuf) { + this.surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, pixbuf.width, pixbuf.height); + + var ctx = this.context(); + Gdk.cairo_set_source_pixbuf(ctx, pixbuf, 1.0, 1.0); + ctx.paint(); + } + + ///////////////////////////////////////////////////////////////////// + /// Paints the image onto the given Cairo.Context + ///////////////////////////////////////////////////////////////////// + + public void paint_on(Cairo.Context ctx, double alpha = 1.0) { + ctx.set_source_surface(this.surface, -0.5*this.width()-1, -0.5*this.height()-1); + if (alpha >= 1.0) ctx.paint(); + else ctx.paint_with_alpha(alpha); + } + + ///////////////////////////////////////////////////////////////////// + /// Returns a Cairo.Context for the Image. + ///////////////////////////////////////////////////////////////////// + + public Cairo.Context context() { + return new Cairo.Context(this.surface);; + } + + ///////////////////////////////////////////////////////////////////// + /// Returns the width of the image in pixels. + ///////////////////////////////////////////////////////////////////// + + public int width() { + return this.surface.get_width(); + } + + ///////////////////////////////////////////////////////////////////// + /// Returns the height of the image in pixels. + ///////////////////////////////////////////////////////////////////// + + public int height() { + return this.surface.get_height(); + } +} + +} diff --git a/src/utilities/key.vala b/src/utilities/key.vala new file mode 100644 index 0000000..6700b16 --- /dev/null +++ b/src/utilities/key.vala @@ -0,0 +1,139 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A class which represents a key stroke. It can be used to "press" +/// the associated keys. +///////////////////////////////////////////////////////////////////////// + +public class Key : GLib.Object { + + ///////////////////////////////////////////////////////////////////// + /// Some static members, which are often used by this class. + ///////////////////////////////////////////////////////////////////// + + private static X.Display display; + + private static int shift_code; + private static int ctrl_code; + private static int alt_code; + private static int super_code; + + ///////////////////////////////////////////////////////////////////// + /// A human readable form of the Key's accelerator. + ///////////////////////////////////////////////////////////////////// + + public string label { get; private set; } + + ///////////////////////////////////////////////////////////////////// + /// The accelerator of the Key. + ///////////////////////////////////////////////////////////////////// + + public string accelerator { get; private set; } + + ///////////////////////////////////////////////////////////////////// + /// Keycode and modifiers of this stroke. + ///////////////////////////////////////////////////////////////////// + + private int key_code; + private Gdk.ModifierType modifiers; + + ///////////////////////////////////////////////////////////////////// + /// C'tor, initializes all members. + ///////////////////////////////////////////////////////////////////// + + public Key(string stroke) { + this.accelerator = stroke; + + uint keysym; + Gtk.accelerator_parse(stroke, out keysym, out this.modifiers); + this.key_code = display.keysym_to_keycode(keysym); + this.label = Gtk.accelerator_get_label(keysym, this.modifiers); + } + + ///////////////////////////////////////////////////////////////////// + /// Initializes static members. + ///////////////////////////////////////////////////////////////////// + + static construct { + display = new X.Display(); + + shift_code = display.keysym_to_keycode(Gdk.keyval_from_name("Shift_L")); + ctrl_code = display.keysym_to_keycode(Gdk.keyval_from_name("Control_L")); + alt_code = display.keysym_to_keycode(Gdk.keyval_from_name("Alt_L")); + super_code = display.keysym_to_keycode(Gdk.keyval_from_name("Super_L")); + } + + ///////////////////////////////////////////////////////////////////// + /// Simulates the pressing of the Key . + ///////////////////////////////////////////////////////////////////// + + public void press() { + // store currently pressed modifier keys + Gdk.ModifierType current_modifiers = get_modifiers(); + + // release them and press the desired ones + press_modifiers(current_modifiers, false); + press_modifiers(this.modifiers, true); + + // send events to X + display.flush(); + + // press and release the actual key + X.Test.fake_key_event(this.display, this.key_code, true, 0); + X.Test.fake_key_event(this.display, this.key_code, false, 0); + + // release the pressed modifiers and re-press the keys hold down by the user + press_modifiers(this.modifiers, false); + press_modifiers(current_modifiers, true); + + // send events to X + display.flush(); + } + + ///////////////////////////////////////////////////////////////////// + /// Helper method returning currently hold down modifier keys. + ///////////////////////////////////////////////////////////////////// + + private Gdk.ModifierType get_modifiers() { + Gdk.ModifierType modifiers; + Gdk.Display.get_default().get_pointer(null, null, null, out modifiers); + return modifiers; + } + + ///////////////////////////////////////////////////////////////////// + /// Helper method which 'presses' the desired modifier keys. + ///////////////////////////////////////////////////////////////////// + + private void press_modifiers(Gdk.ModifierType modifiers, bool down) { + if ((modifiers & Gdk.ModifierType.CONTROL_MASK) > 0) + X.Test.fake_key_event(this.display, this.ctrl_code, down, 0); + + if ((modifiers & Gdk.ModifierType.SHIFT_MASK) > 0) + X.Test.fake_key_event(this.display, this.shift_code, down, 0); + + if ((modifiers & Gdk.ModifierType.MOD1_MASK) > 0) + X.Test.fake_key_event(this.display, this.alt_code, down, 0); + + if ((modifiers & Gdk.ModifierType.SUPER_MASK) > 0) + X.Test.fake_key_event(this.display, this.super_code, down, 0); + } +} + +} diff --git a/src/utilities/logger.vala b/src/utilities/logger.vala new file mode 100644 index 0000000..3108ba3 --- /dev/null +++ b/src/utilities/logger.vala @@ -0,0 +1,194 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A static class which beautifies the messages of the default logger. +/// Some of this code is inspired by plank's written by Robert Dyer. +/// Thanks a lot for this project! +///////////////////////////////////////////////////////////////////////// + +public class Logger { + + ///////////////////////////////////////////////////////////////////// + /// If these are set to false, the according messages are not shown + ///////////////////////////////////////////////////////////////////// + + public static bool display_info { get; set; default = true; } + public static bool display_debug { get; set; default = true; } + public static bool display_warning { get; set; default = true; } + public static bool display_error { get; set; default = true; } + + ///////////////////////////////////////////////////////////////////// + /// If true, a time stamp is shown in each message. + ///////////////////////////////////////////////////////////////////// + + public static bool display_time { get; set; default = true; } + + ///////////////////////////////////////////////////////////////////// + /// If true, the origin of the message is shown. In form file:line + ///////////////////////////////////////////////////////////////////// + + public static bool display_file { get; set; default = false; } + + ///////////////////////////////////////////////////////////////////// + /// A regex, used to format the standard message. + ///////////////////////////////////////////////////////////////////// + + private static Regex regex = null; + + ///////////////////////////////////////////////////////////////////// + /// Possible terminal colors. + ///////////////////////////////////////////////////////////////////// + + private enum Color { + BLACK, + RED, + GREEN, + YELLOW, + BLUE, + PURPLE, + TURQUOISE, + WHITE + } + + ///////////////////////////////////////////////////////////////////// + /// Creates the regex and binds the handler. + ///////////////////////////////////////////////////////////////////// + + public static void init() { + try { + regex = new Regex("""(.*)\.vala(:\d+): (.*)"""); + } catch {} + + GLib.Log.set_default_handler(log_func); + } + + ///////////////////////////////////////////////////////////////////// + /// Displays an Info message. + ///////////////////////////////////////////////////////////////////// + + private static void info(string message) { + if (display_info) { + stdout.printf(set_color(Color.GREEN, false) + "[" + get_time() + "MESSAGE]" + message); + } + } + + ///////////////////////////////////////////////////////////////////// + /// Displays a Debug message. + ///////////////////////////////////////////////////////////////////// + + private static void debug(string message) { + if (display_debug) { + stdout.printf(set_color(Color.BLUE, false) + "[" + get_time() + " DEBUG ]" + message); + } + } + + ///////////////////////////////////////////////////////////////////// + /// Displays a Warning message. + ///////////////////////////////////////////////////////////////////// + + private static void warning(string message) { + if (display_warning) { + stdout.printf(set_color(Color.YELLOW, false) + "[" + get_time() + "WARNING]" + message); + } + } + + ///////////////////////////////////////////////////////////////////// + /// Displays a Error message. + ///////////////////////////////////////////////////////////////////// + + private static void error(string message) { + if (display_error) { + stdout.printf(set_color(Color.RED, false) + "[" + get_time() + " ERROR ]" + message); + } + } + + ///////////////////////////////////////////////////////////////////// + /// Helper method which resets the terminal color. + ///////////////////////////////////////////////////////////////////// + + private static string reset_color() { + return "\x001b[0m"; + } + + ///////////////////////////////////////////////////////////////////// + /// Helper method which sets the terminal color. + ///////////////////////////////////////////////////////////////////// + + private static string set_color(Color color, bool bold) { + if (bold) return "\x001b[1;%dm".printf((int)color + 30); + else return "\x001b[0;%dm".printf((int)color + 30); + } + + ///////////////////////////////////////////////////////////////////// + /// Returns the current time in hh:mm:ss:mmmmmm + ///////////////////////////////////////////////////////////////////// + + private static string get_time() { + if (display_time) { + var now = new DateTime.now_local (); + return "%.2d:%.2d:%.2d:%.6d ".printf (now.get_hour (), now.get_minute (), now.get_second (), now.get_microsecond ()); + } else { + return ""; + } + } + + ///////////////////////////////////////////////////////////////////// + /// Helper method to format the message. + ///////////////////////////////////////////////////////////////////// + + private static string create_message(string message) { + if (display_file && regex != null && regex.match(message)) { + var parts = regex.split(message); + return " [%s%s]%s %s\n".printf(parts[1], parts[2], reset_color(), parts[3]); + } else if (regex != null && regex.match(message)) { + var parts = regex.split(message); + return "%s %s\n".printf(reset_color(), parts[3]); + } else { + return reset_color() + " " + message + "\n"; + } + } + + ///////////////////////////////////////////////////////////////////// + /// The handler function. + ///////////////////////////////////////////////////////////////////// + + private static void log_func(string? d, LogLevelFlags flags, string message) { + + switch (flags) { + case LogLevelFlags.LEVEL_ERROR: + case LogLevelFlags.LEVEL_CRITICAL: + error(create_message(message)); + break; + case LogLevelFlags.LEVEL_INFO: + case LogLevelFlags.LEVEL_MESSAGE: + info(create_message(message)); + break; + case LogLevelFlags.LEVEL_DEBUG: + debug(create_message(message)); + break; + case LogLevelFlags.LEVEL_WARNING: + default: + warning(create_message(message)); + break; + } + } +} + +} diff --git a/src/utilities/paths.vala b/src/utilities/paths.vala new file mode 100644 index 0000000..1c42176 --- /dev/null +++ b/src/utilities/paths.vala @@ -0,0 +1,211 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A static class which stores all relevant paths used by Gnome-Pie. +/// These depend upon the location from which the program was launched. +///////////////////////////////////////////////////////////////////////// + +public class Paths : GLib.Object { + + ///////////////////////////////////////////////////////////////////// + /// The file settings file, + /// usually ~/.config/gnome-pie/gnome-pie.conf. + ///////////////////////////////////////////////////////////////////// + + public static string settings { get; private set; default=""; } + + ///////////////////////////////////////////////////////////////////// + /// The file pie configuration file + /// usually ~/.config/gnome-pie/pies.conf. + ///////////////////////////////////////////////////////////////////// + + public static string pie_config { get; private set; default=""; } + + ///////////////////////////////////////////////////////////////////// + /// The directory containing themes installed by the user + /// usually ~/.config/gnome-pie/themes. + ///////////////////////////////////////////////////////////////////// + + public static string local_themes { get; private set; default=""; } + + ///////////////////////////////////////////////////////////////////// + /// The directory containing pre-installed themes + /// usually /usr/share/gnome-pie/themes. + ///////////////////////////////////////////////////////////////////// + + public static string global_themes { get; private set; default=""; } + + ///////////////////////////////////////////////////////////////////// + /// The directory containing locale files + /// usually /usr/share/locale. + ///////////////////////////////////////////////////////////////////// + + public static string locales { get; private set; default=""; } + + ///////////////////////////////////////////////////////////////////// + /// The autostart file of gnome-pie_config + /// usually ~/.config/autostart/gnome-pie.desktop. + ///////////////////////////////////////////////////////////////////// + + public static string autostart { get; private set; default=""; } + + ///////////////////////////////////////////////////////////////////// + /// The path where all pie-launchers are stored + /// usually ~/.config/gnome-pie/launchers. + ///////////////////////////////////////////////////////////////////// + + public static string launchers { get; private set; default=""; } + + ///////////////////////////////////////////////////////////////////// + /// Initializes all values above. + ///////////////////////////////////////////////////////////////////// + + public static void init() { + + // append resources to icon search path to icon theme, if neccasary + try { + var icon_dir = GLib.File.new_for_path(GLib.Path.get_dirname( + GLib.FileUtils.read_link("/proc/self/exe"))).get_child("resources"); + + if (icon_dir.query_exists()) { + string path = icon_dir.get_path(); + Gtk.IconTheme.get_default().append_search_path(path); + } + + Gtk.IconTheme.get_default().append_search_path("/usr/share/pixmaps/"); + + } catch (GLib.FileError e) { + warning("Failed to get path of executable!"); + } + + // get global paths + var default_dir = GLib.File.new_for_path("/usr/share/gnome-pie/"); + if(!default_dir.query_exists()) { + default_dir = GLib.File.new_for_path("/usr/local/share/gnome-pie/"); + + if(!default_dir.query_exists()) { + try { + default_dir = GLib.File.new_for_path(GLib.Path.get_dirname( + GLib.FileUtils.read_link("/proc/self/exe"))).get_child("resources"); + } catch (GLib.FileError e) { + warning("Failed to get path of executable!"); + } + } + } + + global_themes = default_dir.get_path() + "/themes"; + + // get locales path + var locale_dir = GLib.File.new_for_path("/usr/share/locale/de/LC_MESSAGES/gnomepie.mo"); + if(locale_dir.query_exists()) { + locale_dir = GLib.File.new_for_path("/usr/share/locale"); + } else { + locale_dir = GLib.File.new_for_path("/usr/local/share/locale/de/LC_MESSAGES/gnomepie.mo"); + if(locale_dir.query_exists()) { + locale_dir = GLib.File.new_for_path("/usr/local/share/locale"); + } else { + + try { + locale_dir = GLib.File.new_for_path(GLib.Path.get_dirname( + GLib.FileUtils.read_link("/proc/self/exe"))).get_child( + "resources/locale/de/LC_MESSAGES/gnomepie.mo"); + } catch (GLib.FileError e) { + warning("Failed to get path of executable!"); + } + + if(locale_dir.query_exists()) { + try { + locale_dir = GLib.File.new_for_path(GLib.Path.get_dirname( + GLib.FileUtils.read_link("/proc/self/exe"))).get_child("resources/locale"); + } catch (GLib.FileError e) { + warning("Failed to get path of executable!"); + } + } + } + } + + locales = locale_dir.get_path(); + + // get local paths + var config_dir = GLib.File.new_for_path( + GLib.Environment.get_user_config_dir()).get_child("gnome-pie"); + + // create config_dir if neccasary + if(!config_dir.query_exists()) { + try { + config_dir.make_directory(); + } catch (GLib.Error e) { + error(e.message); + } + } + + // create local themes directory if neccasary + var themes_dir = config_dir.get_child("themes"); + if(!themes_dir.query_exists()) { + try { + themes_dir.make_directory(); + } catch (GLib.Error e) { + error(e.message); + } + } + + local_themes = themes_dir.get_path(); + + // create launchers directory if neccasary + var launchers_dir = config_dir.get_child("launchers"); + if(!launchers_dir.query_exists()) { + try { + launchers_dir.make_directory(); + } catch (GLib.Error e) { + error(e.message); + } + } + + launchers = launchers_dir.get_path(); + + // check for config file + var config_file = config_dir.get_child("pies.conf"); + + pie_config = config_file.get_path(); + settings = config_dir.get_path() + "/gnome-pie.conf"; + + // autostart file name + autostart = GLib.Path.build_filename(GLib.Environment.get_user_config_dir(), + "autostart", "gnome-pie.desktop", null); + + // print results + if (!GLib.File.new_for_path(pie_config).query_exists()) + warning("Failed to find pie configuration file \"pies.conf\"! (This should only happen when Gnome-Pie is started for the first time...)"); + + if (!GLib.File.new_for_path(settings).query_exists()) + warning("Failed to find settings file \"gnome-pie.conf\"!"); + + if (!GLib.File.new_for_path(local_themes).query_exists()) + warning("Failed to find local themes directory!"); + + if (!GLib.File.new_for_path(launchers).query_exists()) + warning("Failed to find launchers directory!"); + + if (!GLib.File.new_for_path(global_themes).query_exists()) + warning("Failed to find global themes directory!"); + } +} + +} diff --git a/src/utilities/renderedText.vala b/src/utilities/renderedText.vala new file mode 100644 index 0000000..924742a --- /dev/null +++ b/src/utilities/renderedText.vala @@ -0,0 +1,110 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A class representing string, rendered on an Image. +///////////////////////////////////////////////////////////////////////// + +public class RenderedText : Image { + + ///////////////////////////////////////////////////////////////////// + /// A cache which stores images. It is cleared when the theme of + /// Gnome-Pie changes. + /// The key is in form @x:. + ///////////////////////////////////////////////////////////////////// + + private static Gee.HashMap cache { private get; private set; } + + ///////////////////////////////////////////////////////////////////// + /// Initializes the cache. + ///////////////////////////////////////////////////////////////////// + + public static void init() { + clear_cache(); + + Config.global.notify["theme"].connect(() => { + clear_cache(); + }); + } + + ///////////////////////////////////////////////////////////////////// + /// Clears the cache. + ///////////////////////////////////////////////////////////////////// + + static void clear_cache() { + cache = new Gee.HashMap(); + } + + ///////////////////////////////////////////////////////////////////// + /// C'tor, creates a new image representation of a string. + ///////////////////////////////////////////////////////////////////// + + public RenderedText(string text, int width, int height, string font) { + var cached = this.cache.get("%s@%ux%u:%s".printf(text, width, height, font)); + + if (cached == null) { + this.render_text(text, width, height, font); + this.cache.set("%s@%ux%u:%s".printf(text, width, height, font), this.surface); + } else { + this.surface = cached; + } + } + + ///////////////////////////////////////////////////////////////////// + /// Creates a new transparent image, with text written onto. + ///////////////////////////////////////////////////////////////////// + + public void render_text(string text, int width, int height, string font) { + this.surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, width, height); + + var ctx = this.context(); + + // set the color as specified in the current theme + Color color = Config.global.theme.caption_color; + ctx.set_source_rgb(color.r, color.g, color.g); + + var layout = Pango.cairo_create_layout(ctx); + layout.set_width(Pango.units_from_double(width)); + + var font_description = Pango.FontDescription.from_string(font); + font_description.set_size((int)(font_description.get_size() * Config.global.global_scale)); + + layout.set_font_description(font_description); + layout.set_text(text, -1); + + // add newlines at the end of each line, in order to allow ellipsizing + string broken_string = ""; + foreach (var line in layout.get_lines()) { + broken_string = broken_string.concat(text.substring(line.start_index, line.length), "\n"); + } + layout.set_text(broken_string, broken_string.length-1); + + layout.set_ellipsize(Pango.EllipsizeMode.END); + layout.set_alignment(Pango.Alignment.CENTER); + + Pango.Rectangle extents; + layout.get_pixel_extents(null, out extents); + ctx.move_to(0, (int)(0.5*(height - extents.height))); + + Pango.cairo_update_layout(ctx, layout); + Pango.cairo_show_layout(ctx, layout); + } +} + +} diff --git a/src/utilities/themedIcon.vala b/src/utilities/themedIcon.vala new file mode 100644 index 0000000..29ae380 --- /dev/null +++ b/src/utilities/themedIcon.vala @@ -0,0 +1,161 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +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 3 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, see . +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A class representing a square-shaped icon, themed according to the +/// current theme of Gnome-Pie. +///////////////////////////////////////////////////////////////////////// + +public class ThemedIcon : Image { + + ///////////////////////////////////////////////////////////////////// + /// A cache which stores loaded icon. The key is the icon name. When + /// the users icon theme or the theme of Gnome-Pie changes, these + /// cahces are cleared. + ///////////////////////////////////////////////////////////////////// + + private static Gee.HashMap active_cache { private get; private set; } + private static Gee.HashMap inactive_cache { private get; private set; } + + ///////////////////////////////////////////////////////////////////// + /// Initializes the caches. + ///////////////////////////////////////////////////////////////////// + + public static void init() { + clear_cache(); + + Config.global.notify["theme"].connect(() => { + clear_cache(); + }); + + Gtk.IconTheme.get_default().changed.connect(() => { + clear_cache(); + }); + } + + ///////////////////////////////////////////////////////////////////// + /// Clears the cache. + ///////////////////////////////////////////////////////////////////// + + public static void clear_cache() { + active_cache = new Gee.HashMap(); + inactive_cache = new Gee.HashMap(); + } + + ///////////////////////////////////////////////////////////////////// + /// Paint a slice icon according to the current theme. + ///////////////////////////////////////////////////////////////////// + + public ThemedIcon(string icon_name, bool active) { + // check cache + var current_cache = active ? active_cache : inactive_cache; + var cached = current_cache.get(icon_name); + + if (cached != null) { + this.surface = cached; + return; + } + + // get layers for the desired slice type + var layers = active ? Config.global.theme.active_slice_layers : Config.global.theme.inactive_slice_layers; + + // get max size + int size = 0; + foreach (var layer in layers) { + if (layer.image.width() > size) size = layer.image.width(); + } + + this.surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, size, size); + + // get size of icon layer + int icon_size = size; + foreach (var layer in layers) { + if (layer.is_icon) icon_size = layer.image.width(); + } + + Image icon; + if (icon_name.contains("/")) + icon = new Image.from_file_at_size(icon_name, icon_size, icon_size); + else + icon = new Icon(icon_name, icon_size); + + var color = new Color.from_icon(icon); + var ctx = this.context(); + + ctx.translate(size/2, size/2); + ctx.set_operator(Cairo.Operator.OVER); + + // now render all layers on top of each other + foreach (var layer in layers) { + + if (layer.colorize) { + ctx.push_group(); + } + + if (layer.is_icon) { + + ctx.push_group(); + + layer.image.paint_on(ctx); + + ctx.set_operator(Cairo.Operator.IN); + + if (layer.image.width() != icon_size) { + if (icon_name.contains("/")) + icon = new Image.from_file_at_size(icon_name, layer.image.width(), layer.image.width()); + else + icon = new Icon(icon_name,layer.image.width()); + } + + icon.paint_on(ctx); + + ctx.pop_group_to_source(); + ctx.paint(); + ctx.set_operator(Cairo.Operator.OVER); + + } else { + layer.image.paint_on(ctx); + } + + // colorize the whole layer if neccasary + if (layer.colorize) { + ctx.set_operator(Cairo.Operator.ATOP); + ctx.set_source_rgb(color.r, color.g, color.b); + ctx.paint(); + + ctx.set_operator(Cairo.Operator.OVER); + ctx.pop_group_to_source(); + ctx.paint(); + } + } + + // store the surface in cache + current_cache.set(icon_name, this.surface); + } + + ///////////////////////////////////////////////////////////////////// + /// Returns the size of the icon in pixels. Greetings to Liskov. + ///////////////////////////////////////////////////////////////////// + + public int size() { + return base.width(); + } +} + +} diff --git a/vapi/appindicator-0.1.vapi b/vapi/appindicator-0.1.vapi new file mode 100644 index 0000000..b2d3b34 --- /dev/null +++ b/vapi/appindicator-0.1.vapi @@ -0,0 +1,94 @@ +/* appindicator-0.1.vapi generated by vapigen, do not modify. */ + +[CCode (cprefix = "App", lower_case_cprefix = "app_", gir_namespace = "AppIndicator", gir_version = "0.1")] +namespace AppIndicator { + [CCode (cheader_filename = "libappindicator/app-indicator.h")] + public class Indicator : GLib.Object { + public AppIndicator.IndicatorPrivate priv; + [CCode (has_construct_function = false)] + public Indicator (string id, string icon_name, AppIndicator.IndicatorCategory category); + public void build_menu_from_desktop (string desktop_file, string desktop_profile); + public unowned string get_attention_icon (); + public unowned string get_attention_icon_desc (); + public AppIndicator.IndicatorCategory get_category (); + public unowned string get_icon (); + public unowned string get_icon_desc (); + public unowned string get_icon_theme_path (); + public unowned string get_id (); + public unowned string get_label (); + public unowned string get_label_guide (); + public unowned Gtk.Menu get_menu (); + public uint32 get_ordering_index (); + public unowned Gtk.Widget get_secondary_activate_target (); + public AppIndicator.IndicatorStatus get_status (); + public void set_attention_icon (string icon_name); + public void set_attention_icon_full (string icon_name, string icon_desc); + public void set_icon (string icon_name); + public void set_icon_full (string icon_name, string icon_desc); + public void set_icon_theme_path (string icon_theme_path); + public void set_label (string label, string guide); + public void set_menu (Gtk.Menu? menu); + public void set_ordering_index (uint32 ordering_index); + public void set_secondary_activate_target (Gtk.Widget? menuitem); + public void set_status (AppIndicator.IndicatorStatus status); + [NoWrapper] + public virtual void unfallback (Gtk.StatusIcon status_icon); + [CCode (has_construct_function = false)] + public Indicator.with_path (string id, string icon_name, AppIndicator.IndicatorCategory category, string icon_theme_path); + public string attention_icon_desc { get; set; } + [NoAccessorMethod] + public string attention_icon_name { get; set; } + public string category { get; construct; } + [NoAccessorMethod] + public bool connected { get; } + public string icon_desc { get; set; } + [NoAccessorMethod] + public string icon_name { get; set; } + public string icon_theme_path { get; set construct; } + public string id { get; construct; } + public string label { get; set; } + public string label_guide { get; set; } + public uint ordering_index { get; set; } + public string status { get; set; } + public virtual signal void connection_changed (bool indicator); + public virtual signal void new_attention_icon (); + public virtual signal void new_icon (); + public virtual signal void new_icon_theme_path (string indicator); + public virtual signal void new_label (string indicator, string label); + public virtual signal void new_status (string indicator); + public virtual signal void scroll_event (int indicator, uint delta); + } + [CCode (type_id = "APP_TYPE_INDICATOR_PRIVATE", cheader_filename = "libappindicator/app-indicator.h")] + public struct IndicatorPrivate { + } + [CCode (cprefix = "APP_INDICATOR_CATEGORY_", cheader_filename = "libappindicator/app-indicator.h")] + public enum IndicatorCategory { + APPLICATION_STATUS, + COMMUNICATIONS, + SYSTEM_SERVICES, + HARDWARE, + OTHER + } + [CCode (cprefix = "APP_INDICATOR_STATUS_", cheader_filename = "libappindicator/app-indicator.h")] + public enum IndicatorStatus { + PASSIVE, + ACTIVE, + ATTENTION + } + [CCode (cheader_filename = "libappindicator/app-indicator.h")] + public const string INDICATOR_SHORTY_NICK; + [CCode (cheader_filename = "libappindicator/app-indicator.h")] + public const string INDICATOR_SIGNAL_CONNECTION_CHANGED; + [CCode (cheader_filename = "libappindicator/app-indicator.h")] + public const string INDICATOR_SIGNAL_NEW_ATTENTION_ICON; + [CCode (cheader_filename = "libappindicator/app-indicator.h")] + public const string INDICATOR_SIGNAL_NEW_ICON; + [CCode (cheader_filename = "libappindicator/app-indicator.h")] + public const string INDICATOR_SIGNAL_NEW_ICON_THEME_PATH; + [CCode (cheader_filename = "libappindicator/app-indicator.h")] + public const string INDICATOR_SIGNAL_NEW_LABEL; + [CCode (cheader_filename = "libappindicator/app-indicator.h")] + public const string INDICATOR_SIGNAL_NEW_STATUS; + [CCode (cheader_filename = "libappindicator/app-indicator.h")] + public const string INDICATOR_SIGNAL_SCROLL_EVENT; +} diff --git a/vapi/gee-1.0.vapi b/vapi/gee-1.0.vapi new file mode 100644 index 0000000..fe9ea6c --- /dev/null +++ b/vapi/gee-1.0.vapi @@ -0,0 +1,416 @@ +/* gee-1.0.vapi generated by valac-0.12 0.12.1, do not modify. */ + +[CCode (cprefix = "Gee", lower_case_cprefix = "gee_", gir_namespace = "Gee", gir_version = "1.0")] +namespace Gee { + [CCode (cprefix = "GeeFunctions", lower_case_cprefix = "gee_functions_")] + namespace Functions { + [CCode (cheader_filename = "gee.h")] + public static GLib.CompareFunc get_compare_func_for (GLib.Type t); + [CCode (cheader_filename = "gee.h")] + public static GLib.EqualFunc get_equal_func_for (GLib.Type t); + [CCode (cheader_filename = "gee.h")] + public static GLib.HashFunc get_hash_func_for (GLib.Type t); + } + [CCode (cheader_filename = "gee.h")] + public abstract class AbstractCollection : GLib.Object, Gee.Iterable, Gee.Collection { + public AbstractCollection (); + public abstract bool add (G item); + public virtual bool add_all (Gee.Collection collection); + public abstract void clear (); + public abstract bool contains (G item); + public virtual bool contains_all (Gee.Collection collection); + public abstract Gee.Iterator iterator (); + public abstract bool remove (G item); + public virtual bool remove_all (Gee.Collection collection); + public virtual bool retain_all (Gee.Collection collection); + public virtual G[] to_array (); + public virtual bool is_empty { get; } + public virtual Gee.Collection read_only_view { owned get; } + public abstract int size { get; } + } + [CCode (cheader_filename = "gee.h")] + public abstract class AbstractList : Gee.AbstractCollection, Gee.List { + public AbstractList (); + public virtual G first (); + public abstract new G @get (int index); + public abstract int index_of (G item); + public abstract void insert (int index, G item); + public virtual void insert_all (int index, Gee.Collection collection); + public virtual G last (); + public abstract Gee.ListIterator list_iterator (); + public abstract G remove_at (int index); + public abstract new void @set (int index, G item); + public abstract Gee.List? slice (int start, int stop); + public virtual Gee.List read_only_view { owned get; } + } + [CCode (cheader_filename = "gee.h")] + public abstract class AbstractMap : GLib.Object, Gee.Iterable>, Gee.Map { + public AbstractMap (); + public abstract void clear (); + public abstract new V @get (K key); + public abstract bool has (K key, V value); + public virtual bool has_all (Gee.Map map); + public abstract bool has_key (K key); + public abstract Gee.MapIterator map_iterator (); + public abstract new void @set (K key, V value); + public virtual void set_all (Gee.Map map); + public abstract bool unset (K key, out V value = null); + public virtual bool unset_all (Gee.Map map); + public abstract Gee.Set> entries { owned get; } + public virtual bool is_empty { get; } + public abstract Gee.Set keys { owned get; } + public virtual Gee.Map read_only_view { owned get; } + public abstract int size { get; } + public abstract Gee.Collection values { owned get; } + } + [CCode (cheader_filename = "gee.h")] + public abstract class AbstractMultiMap : GLib.Object, Gee.MultiMap { + protected Gee.Map> _storage_map; + public AbstractMultiMap (Gee.Map> storage_map); + protected abstract Gee.MultiSet create_multi_key_set (); + protected abstract Gee.Collection create_value_storage (); + protected abstract GLib.EqualFunc get_value_equal_func (); + } + [CCode (cheader_filename = "gee.h")] + public abstract class AbstractMultiSet : Gee.AbstractCollection, Gee.MultiSet { + protected Gee.Map _storage_map; + public AbstractMultiSet (Gee.Map storage_map); + public override bool add (G item); + public override void clear (); + public override bool contains (G item); + public override Gee.Iterator iterator (); + public override bool remove (G item); + public override int size { get; } + } + [CCode (cheader_filename = "gee.h")] + public abstract class AbstractQueue : Gee.AbstractCollection, Gee.Queue { + public AbstractQueue (); + public abstract int drain (Gee.Collection recipient, int amount = -1); + public abstract bool offer (G element); + public abstract G peek (); + public abstract G poll (); + public abstract int capacity { get; } + public abstract bool is_full { get; } + public abstract int remaining_capacity { get; } + } + [CCode (cheader_filename = "gee.h")] + public abstract class AbstractSet : Gee.AbstractCollection, Gee.Set { + public AbstractSet (); + public virtual Gee.Set read_only_view { owned get; } + } + [CCode (cheader_filename = "gee.h")] + public class ArrayList : Gee.AbstractList { + public ArrayList (GLib.EqualFunc? equal_func = null); + public override bool add (G item); + public override bool add_all (Gee.Collection collection); + public override void clear (); + public override bool contains (G item); + public override G @get (int index); + public override int index_of (G item); + public override void insert (int index, G item); + public override Gee.Iterator iterator (); + public override Gee.ListIterator list_iterator (); + public override bool remove (G item); + public override G remove_at (int index); + public override void @set (int index, G item); + public override Gee.List? slice (int start, int stop); + public void sort_with_data (GLib.CompareDataFunc compare); + public GLib.EqualFunc equal_func { get; private set; } + public override int size { get; } + } + [CCode (cheader_filename = "gee.h")] + public class HashMap : Gee.AbstractMap { + public HashMap (GLib.HashFunc? key_hash_func = null, GLib.EqualFunc? key_equal_func = null, GLib.EqualFunc? value_equal_func = null); + public override void clear (); + public override V @get (K key); + public override bool has (K key, V value); + public override bool has_key (K key); + public override Gee.MapIterator map_iterator (); + public override void @set (K key, V value); + public override bool unset (K key, out V value = null); + public override Gee.Set> entries { owned get; } + public GLib.EqualFunc key_equal_func { get; private set; } + public GLib.HashFunc key_hash_func { get; private set; } + public override Gee.Set keys { owned get; } + public override int size { get; } + public GLib.EqualFunc value_equal_func { get; private set; } + public override Gee.Collection values { owned get; } + } + [CCode (cheader_filename = "gee.h")] + public class HashMultiMap : Gee.AbstractMultiMap { + public HashMultiMap (GLib.HashFunc? key_hash_func = null, GLib.EqualFunc? key_equal_func = null, GLib.HashFunc? value_hash_func = null, GLib.EqualFunc? value_equal_func = null); + protected override Gee.MultiSet create_multi_key_set (); + protected override Gee.Collection create_value_storage (); + protected override GLib.EqualFunc get_value_equal_func (); + public GLib.EqualFunc key_equal_func { get; } + public GLib.HashFunc key_hash_func { get; } + public GLib.EqualFunc value_equal_func { get; private set; } + public GLib.HashFunc value_hash_func { get; private set; } + } + [CCode (cheader_filename = "gee.h")] + public class HashMultiSet : Gee.AbstractMultiSet { + public HashMultiSet (GLib.HashFunc? hash_func = null, GLib.EqualFunc? equal_func = null); + public GLib.EqualFunc equal_func { get; } + public GLib.HashFunc hash_func { get; } + } + [CCode (cheader_filename = "gee.h")] + public class HashSet : Gee.AbstractSet { + public HashSet (GLib.HashFunc? hash_func = null, GLib.EqualFunc? equal_func = null); + public override bool add (G key); + public override void clear (); + public override bool contains (G key); + public override Gee.Iterator iterator (); + public override bool remove (G key); + public GLib.EqualFunc equal_func { get; private set; } + public GLib.HashFunc hash_func { get; private set; } + public override int size { get; } + } + [CCode (cheader_filename = "gee.h")] + public class LinkedList : Gee.AbstractList, Gee.Queue, Gee.Deque { + public LinkedList (GLib.EqualFunc? equal_func = null); + public override bool add (G item); + public override void clear (); + public override bool contains (G item); + public override G first (); + public override G @get (int index); + public override int index_of (G item); + public override void insert (int index, G item); + public override Gee.Iterator iterator (); + public override G last (); + public override Gee.ListIterator list_iterator (); + public override bool remove (G item); + public override G remove_at (int index); + public override void @set (int index, G item); + public override Gee.List? slice (int start, int stop); + public GLib.EqualFunc equal_func { get; private set; } + public override int size { get; } + } + [CCode (cheader_filename = "gee.h")] + public class PriorityQueue : Gee.AbstractQueue { + public PriorityQueue (GLib.CompareFunc? compare_func = null); + public override bool add (G item); + public override void clear (); + public override bool contains (G item); + public override int drain (Gee.Collection recipient, int amount = -1); + public override Gee.Iterator iterator (); + public override bool offer (G element); + public override G peek (); + public override G poll (); + public override bool remove (G item); + public override int capacity { get; } + public GLib.CompareFunc compare_func { get; private set; } + public override bool is_full { get; } + public override int remaining_capacity { get; } + public override int size { get; } + } + [CCode (cheader_filename = "gee.h")] + public class TreeMap : Gee.AbstractMap { + public TreeMap (GLib.CompareFunc? key_compare_func = null, GLib.EqualFunc? value_equal_func = null); + public override void clear (); + public override V @get (K key); + public override bool has (K key, V value); + public override bool has_key (K key); + public override Gee.MapIterator map_iterator (); + public override void @set (K key, V value); + public override bool unset (K key, out V value = null); + public override Gee.Set> entries { owned get; } + public GLib.CompareFunc key_compare_func { get; private set; } + public override Gee.Set keys { owned get; } + public override int size { get; } + public GLib.EqualFunc value_equal_func { get; private set; } + public override Gee.Collection values { owned get; } + } + [CCode (cheader_filename = "gee.h")] + public class TreeMultiMap : Gee.AbstractMultiMap { + public TreeMultiMap (GLib.CompareFunc? key_compare_func = null, GLib.CompareFunc? value_compare_func = null); + protected override Gee.MultiSet create_multi_key_set (); + protected override Gee.Collection create_value_storage (); + protected override GLib.EqualFunc get_value_equal_func (); + public GLib.CompareFunc key_compare_func { get; } + public GLib.CompareFunc value_compare_func { get; private set; } + } + [CCode (cheader_filename = "gee.h")] + public class TreeMultiSet : Gee.AbstractMultiSet { + public TreeMultiSet (GLib.CompareFunc? compare_func = null); + public GLib.CompareFunc compare_func { get; } + } + [CCode (cheader_filename = "gee.h")] + public class TreeSet : Gee.AbstractSet, Gee.SortedSet { + public TreeSet (GLib.CompareFunc? compare_func = null); + public override bool add (G item); + public override void clear (); + public override bool contains (G item); + public override Gee.Iterator iterator (); + public override bool remove (G item); + public GLib.CompareFunc compare_func { get; private set; } + public override int size { get; } + } + [CCode (cheader_filename = "gee.h")] + public interface BidirIterator : Gee.Iterator { + public abstract bool has_previous (); + public abstract bool last (); + public abstract bool previous (); + } + [CCode (cheader_filename = "gee.h")] + public interface Collection : Gee.Iterable { + public abstract bool add (G item); + public abstract bool add_all (Gee.Collection collection); + public abstract void clear (); + public abstract bool contains (G item); + public abstract bool contains_all (Gee.Collection collection); + public static Gee.Collection empty (); + public abstract bool remove (G item); + public abstract bool remove_all (Gee.Collection collection); + public abstract bool retain_all (Gee.Collection collection); + public abstract G[] to_array (); + public abstract bool is_empty { get; } + public abstract Gee.Collection read_only_view { owned get; } + public abstract int size { get; } + } + [CCode (cheader_filename = "gee.h")] + public interface Comparable : GLib.Object { + public abstract int compare_to (G object); + } + [CCode (cheader_filename = "gee.h")] + public interface Deque : Gee.Queue { + public abstract int drain_head (Gee.Collection recipient, int amount = -1); + public abstract int drain_tail (Gee.Collection recipient, int amount = -1); + public abstract bool offer_head (G element); + public abstract bool offer_tail (G element); + public abstract G peek_head (); + public abstract G peek_tail (); + public abstract G poll_head (); + public abstract G poll_tail (); + } + [CCode (cheader_filename = "gee.h")] + public interface Iterable : GLib.Object { + public abstract Gee.Iterator iterator (); + public abstract GLib.Type element_type { get; } + } + [CCode (cheader_filename = "gee.h")] + public interface Iterator : GLib.Object { + public abstract bool first (); + public abstract G @get (); + public abstract bool has_next (); + public abstract bool next (); + public abstract void remove (); + } + [CCode (cheader_filename = "gee.h")] + public interface List : Gee.Collection { + public static Gee.List empty (); + public abstract G first (); + public abstract G @get (int index); + public abstract int index_of (G item); + public abstract void insert (int index, G item); + public abstract void insert_all (int index, Gee.Collection collection); + public abstract G last (); + public abstract new Gee.ListIterator list_iterator (); + public abstract G remove_at (int index); + public abstract void @set (int index, G item); + public abstract Gee.List? slice (int start, int stop); + public abstract void sort (GLib.CompareFunc? compare_func = null); + public abstract Gee.List read_only_view { owned get; } + } + [CCode (cheader_filename = "gee.h")] + public interface ListIterator : Gee.BidirIterator { + public abstract void add (G item); + public abstract int index (); + public abstract void insert (G item); + public abstract void @set (G item); + } + [CCode (cheader_filename = "gee.h")] + public interface Map : GLib.Object, Gee.Iterable> { + [CCode (cheader_filename = "gee.h")] + public abstract class Entry : GLib.Object { + public Entry (); + public abstract K key { get; } + public abstract V value { get; set; } + } + public abstract void clear (); + [Deprecated] + public abstract bool contains (K key); + [Deprecated] + public abstract bool contains_all (Gee.Map map); + public static Gee.Map empty (); + public abstract V @get (K key); + public abstract bool has (K key, V value); + public abstract bool has_all (Gee.Map map); + public abstract bool has_key (K key); + public abstract Gee.MapIterator map_iterator (); + [Deprecated] + public abstract bool remove (K key, out V value = null); + [Deprecated] + public abstract bool remove_all (Gee.Map map); + public abstract void @set (K key, V value); + public abstract void set_all (Gee.Map map); + public abstract bool unset (K key, out V value = null); + public abstract bool unset_all (Gee.Map map); + public abstract Gee.Set> entries { owned get; } + public abstract bool is_empty { get; } + public abstract GLib.Type key_type { get; } + public abstract Gee.Set keys { owned get; } + public abstract Gee.Map read_only_view { owned get; } + public abstract int size { get; } + public abstract GLib.Type value_type { get; } + public abstract Gee.Collection values { owned get; } + } + [CCode (cheader_filename = "gee.h")] + public interface MapIterator : GLib.Object { + public abstract bool first (); + public abstract K get_key (); + public abstract V get_value (); + public abstract bool has_next (); + public abstract bool next (); + public abstract void set_value (V value); + public abstract void unset (); + } + [CCode (cheader_filename = "gee.h")] + public interface MultiMap : GLib.Object { + public abstract void clear (); + public abstract bool contains (K key); + public abstract Gee.Collection @get (K key); + public abstract Gee.MultiSet get_all_keys (); + public abstract Gee.Set get_keys (); + public abstract Gee.Collection get_values (); + public abstract bool remove (K key, V value); + public abstract bool remove_all (K key); + public abstract void @set (K key, V value); + public abstract int size { get; } + } + [CCode (cheader_filename = "gee.h")] + public interface MultiSet : Gee.Collection { + public abstract int count (G item); + } + [CCode (cheader_filename = "gee.h")] + public interface Queue : Gee.Collection { + public const int UNBOUNDED_CAPACITY; + public abstract int drain (Gee.Collection recipient, int amount = -1); + public abstract bool offer (G element); + public abstract G peek (); + public abstract G poll (); + public abstract int capacity { get; } + public abstract bool is_full { get; } + public abstract int remaining_capacity { get; } + } + [CCode (cheader_filename = "gee.h")] + public interface Set : Gee.Collection { + public static Gee.Set empty (); + public abstract Gee.Set read_only_view { owned get; } + } + [CCode (cheader_filename = "gee.h")] + public interface SortedSet : Gee.Set { + public abstract Gee.BidirIterator bidir_iterator (); + public abstract G ceil (G element); + public abstract G first (); + public abstract G floor (G element); + public abstract Gee.SortedSet head_set (G before); + public abstract G higher (G element); + public abstract Gee.BidirIterator? iterator_at (G element); + public abstract G last (); + public abstract G lower (G element); + public abstract Gee.SortedSet sub_set (G from, G to); + public abstract Gee.SortedSet tail_set (G after); + } + [CCode (cheader_filename = "gee.h")] + public static int direct_compare (void* _val1, void* _val2); +} diff --git a/vapi/libgnome-menu-3.0.vapi b/vapi/libgnome-menu-3.0.vapi new file mode 100644 index 0000000..0afbea0 --- /dev/null +++ b/vapi/libgnome-menu-3.0.vapi @@ -0,0 +1,93 @@ +/* libgnome-menu-3.0.vapi generated by vapigen, do not modify. */ + +namespace GMenu { + [CCode (cheader_filename = "gnome-menus-3.0/gmenu-tree.h")] + public class Tree : GLib.Object { + [CCode (has_construct_function = false)] + public Tree (string menu_basename, GMenu.TreeFlags flags); + [CCode (has_construct_function = false)] + public Tree.for_path (string menu_path, GMenu.TreeFlags flags); + public unowned string get_canonical_menu_path (); + public unowned GMenu.TreeDirectory get_directory_from_path (string path); + public unowned GMenu.TreeEntry get_entry_by_id (string id); + public unowned GMenu.TreeDirectory get_root_directory (); + public static void* item_ref (void* item); + public static void item_unref (void* item); + public bool load_sync () throws GLib.Error; + [NoAccessorMethod] + public GMenu.TreeFlags flags { get; construct; } + [NoAccessorMethod] + public string menu_basename { owned get; construct; } + [NoAccessorMethod] + public string menu_path { owned get; construct; } + public virtual signal void changed (); + } + [CCode (cheader_filename = "gnome-menus-3.0/gmenu-tree.h")] + [Compact] + public class TreeAlias { + public unowned GMenu.TreeDirectory get_aliased_directory (); + public unowned GMenu.TreeEntry get_aliased_entry (); + public GMenu.TreeItemType get_aliased_item_type (); + public unowned GMenu.TreeDirectory get_directory (); + } + [CCode (cheader_filename = "gnome-menus-3.0/gmenu-tree.h")] + [Compact] + public class TreeDirectory { + public unowned string get_comment (); + public unowned string get_desktop_file_path (); + public unowned string get_generic_name (); + public unowned GLib.Icon get_icon (); + public bool get_is_nodisplay (); + public unowned string get_menu_id (); + public unowned string get_name (); + public unowned GMenu.TreeDirectory get_parent (); + public unowned GMenu.TreeIter iter (); + public unowned string make_path (GMenu.TreeEntry entry); + } + [CCode (cheader_filename = "gnome-menus-3.0/gmenu-tree.h")] + [Compact] + public class TreeEntry { + public unowned GLib.DesktopAppInfo get_app_info (); + public unowned string get_desktop_file_id (); + public unowned string get_desktop_file_path (); + public bool get_is_excluded (); + public unowned GMenu.TreeDirectory get_parent (); + } + [CCode (cheader_filename = "gnome-menus-3.0/gmenu-tree.h")] + [Compact] + public class TreeHeader { + public unowned GMenu.TreeDirectory get_directory (); + } + [CCode (cheader_filename = "gnome-menus-3.0/gmenu-tree.h", ref_function = "gmenu_tree_iter_ref", unref_function = "gmenu_tree_iter_unref")] + [Compact] + public class TreeIter { + public unowned GMenu.TreeAlias get_alias (); + public unowned GMenu.TreeDirectory get_directory (); + public unowned GMenu.TreeEntry get_entry (); + public unowned GMenu.TreeHeader get_header (); + public GMenu.TreeItemType next (); + } + [CCode (cheader_filename = "gnome-menus-3.0/gmenu-tree.h")] + [Compact] + public class TreeSeparator { + } + [CCode (cheader_filename = "gnome-menus-3.0/gmenu-tree.h", cprefix = "GMENU_TREE_FLAGS_")] + [Flags] + public enum TreeFlags { + NONE, + INCLUDE_EXCLUDED, + SHOW_EMPTY, + INCLUDE_NODISPLAY, + SHOW_ALL_SEPARATORS, + SORT_DISPLAY_NAME + } + [CCode (cheader_filename = "gnome-menus-3.0/gmenu-tree.h", cprefix = "GMENU_TREE_ITEM_", has_type_id = false)] + public enum TreeItemType { + INVALID, + DIRECTORY, + ENTRY, + SEPARATOR, + HEADER, + ALIAS + } +} diff --git a/vapi/x11.vapi b/vapi/x11.vapi new file mode 100644 index 0000000..cf80228 --- /dev/null +++ b/vapi/x11.vapi @@ -0,0 +1,996 @@ +/* x11.vapi + * + * Copyright (C) 2009 Jürg Billeter + * Copyright (C) 2011 Alexander Kurtz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Jürg Billeter + * Alexander Kurtz + */ + +[CCode (cprefix = "", lower_case_cprefix = "", cheader_filename = "X11/Xlib.h,X11/Xatom.h,X11/Xutil.h,X11/Xregion.h")] +namespace X { + // Note: must be called before opening a display or calling any other Xlib function, + // see http://tronche.com/gui/x/xlib/display/XInitThreads.html + [CCode (cname = "XInitThreads")] + public Status init_threads (); + + [Compact] + [CCode (cname = "Display", ref_function = "", unref_function = "")] + public class Display { + [CCode (cname = "XOpenDisplay")] + public Display (string? name = null); + + [CCode (cname = "XAllPlanes")] + public static ulong get_all_planes (); + + [CCode (cname = "XActivateScreenSaver")] + public void activate_screensaver (); + + [CCode (cname = "XAddToSaveSet")] + public int add_to_save_set (Window w); + + [CCode (cname = "XAllowEvents")] + public int allow_events (int event_mode, int time); + + [CCode (cname = "XBitmapBitOrder")] + public int bitmap_bit_order (); + + [CCode (cname = "XBitmapUnit")] + public int bitmap_scanline_unit (); + + [CCode (cname = "XBitmapPad")] + public int bitmap_scanline_padding (); + + [CCode (cname = "XChangeProperty")] + public int change_property (Window w, Atom property, Atom type, int format, int mode, [CCode (array_length = false)] uchar[] data, int nelements); + + [CCode (cname = "XChangeWindowAttributes")] + public int change_window_attributes (Window w, ulong valuemask, SetWindowAttributes attributes); + + [CCode (cname = "XConfigureWindow")] + public int configure_window (Window w, uint value_mask, WindowChanges values); + + [CCode (cname = "ConnectionNumber")] + public int connection_number (); + + [CCode (cname = "DefaultRootWindow")] + public Window default_root_window (); + + [CCode (cname = "XDefaultScreenOfDisplay")] + public unowned Screen default_screen (); + + [CCode (cname = "XScreenOfDisplay")] + public unowned Screen screen_by_id (int screen_number); + + [CCode (cname = "DisplayString")] + public string display_string (); + + [CCode (cname = "XQLength")] + public int event_queue_length (); + + [CCode (cname = "XFlush")] + public int flush (); + + [CCode (cname = "XForceScreenSaver")] + public void force_screensaver (int mode); + + [CCode (cname = "XGetKeyboardMapping", array_length = false)] + public unowned uint[] get_keyboard_mapping (uint first_keycode, int keycode_count, ref int keysyms_per_keycode_return); + + [CCode (cname = "XGetModifierMapping")] + public ModifierKeymap get_modifier_mapping (); + + [CCode (cname = "XGetScreenSaver")] + public void get_screensaver (out int timeout, out int interval, out int prefer_blanking, out int allow_exposures); + + [CCode (cname = "XGetSelectionOwner")] + public Window get_selection_owner (Atom selection); + + [CCode (cname = "XGetWindowAttributes")] + public void get_window_attributes (Window w, out WindowAttributes window_attributes_return); + + [CCode (cname = "XGetWindowProperty")] + public int get_window_property (Window w, Atom property, long long_offset, long long_length, bool delete, Atom req_type, out Atom actual_type_return, out int actual_format_return, out ulong nitems_return, out ulong bytes_after_return, [CCode (type = "unsigned char **")] out void* prop_return); + + [CCode (cname = "XGrabButton")] + public int grab_button (uint button, uint modifiers, Window grab_window, bool owner_events, uint event_mask, int pointer_mode, int keyboard_mode, Window confine_to, uint cursor); + + [CCode (cname = "XGrabKey")] + public int grab_key (int keycode, uint modifiers, Window grab_window, bool owner_events, int pointer_mode, int keyboard_mode); + + [CCode (cname = "XGrabPointer")] + public int grab_pointer (Window grab_window, bool owner_events, uint event_mask, int pointer_mode, int keyboard_mode, Window confine_to, uint cursor, int time); + + [CCode (cname = "XGrabServer")] + public int grab_server (); + + [CCode (cname = "XImageByteOrder")] + public int image_byte_order (); + + [CCode (cname = "XInternAtom")] + public Atom intern_atom (string atom_name, bool only_if_exists); + + [CCode (cname = "XInternAtoms")] + public void intern_atoms (string[] names, bool only_if_exists, [CCode (array_length = false)] Atom[] atoms_return); + + [CCode (cname = "XInternalConnectionNumbers")] + public Status internal_connection_numbers (ref int[] fd_return); + + [CCode (cname = "XDisplayKeycodes")] + public int keycodes (ref int min_keycodes_return, ref int max_keycodes_return); + + [CCode (cname = "XKeysymToKeycode")] + public int keysym_to_keycode (uint keysym); + + [CCode (cname = "XLastKnownRequestProcessed")] + public ulong last_known_request_processed (); + + [CCode (cname = "XLockDisplay")] + public void lock_display (); + + [CCode (cname = "XMapWindow")] + public int map_window (Window w); + + [CCode (cname = "XMaxRequestSize")] + public long max_request_size (); + + [CCode (cname = "XExtendedMaxRequestSize")] + public long max_extended_request_size (); + + [CCode (cname = "XEventsQueued")] + public int events_queued (int mode); + + [CCode (cname = "XNextEvent")] + public int next_event (ref Event event_return); + + [CCode (cname = "XNextRequest")] + public ulong next_request (); + + [CCode (cname = "XNoOp")] + public void no_operation (); + + [CCode (cname = "XScreenCount")] + public int number_of_screens (); + + [CCode (cname = "XPending")] + public int pending (); + + [CCode (cname = "XProcessInternalConnection")] + public void process_internal_connection (int fd); + + [CCode (cname = "XProtocolVersion")] + public int protocol_version (); + + [CCode (cname = "XProtocolRevision")] + public int protocol_revision (); + + [CCode (cname = "XRaiseWindow")] + public int raise_window (Window w); + + [CCode (cname = "XReparentWindow")] + public int reparent_window (Window w, Window parent, int x, int y); + + [CCode (cname = "XResetScreenSaver")] + public void reset_screensaver (); + + [CCode (cname = "XResizeWindow")] + public int resize_window (Window w, uint width, uint height); + + [CCode (cname = "XRootWindow")] + public Window root_window (int screen_number); + + [CCode (cname = "ScreenCount")] + public int screen_count (); + + [CCode (cname = "XScreenOfDisplay")] + public unowned Screen screen_of_display (int screen_number); + + [CCode (cname = "XSelectInput")] + public int select_input (Window w, long event_mask); + + [CCode (cname = "XSendEvent")] + public void send_event (Window w, bool propagate, long event_mask, ref Event event_send); + + [CCode (cname = "XSetCloseDownMode")] + public void set_close_down_mode (int close_mode); + + [CCode (cname = "XSetScreenSaver")] + public void set_screensaver (int timeout, int interval, int prefer_blanking, int allow_exposures); + + [CCode (cname = "XSetSelectionOwner")] + public Window set_selection_owner (Atom selection, Window owner, int time); + + [CCode (cname = "XSetInputFocus")] + public int set_input_focus (Window focus, int revert_to, int time); + + [CCode (cname = "XUngrabButton")] + public int ungrab_button (uint button, uint modifiers, Window grab_window); + + [CCode (cname = "XUngrabKey")] + public int ungrab_key (int keycode, uint modifiers, Window grab_window); + + [CCode (cname = "XUngrabPointer")] + public int ungrab_pointer (int time); + + [CCode (cname = "XUngrabServer")] + public int ungrab_server (); + + [CCode (cname = "XUnlockDisplay")] + public void unlock_display (); + + [CCode (cname = "XUnmapWindow")] + public int unmap_window (Window w); + + [CCode (cname = "XQueryTree")] + public void query_tree (Window w, out Window root_return, out Window parent_return, out Window[] children_return); + + [CCode (cname = "XWindowEvent")] + public int window_event (Window w, EventMask event_mask, out Event event_return); + + [CCode (cname = "XServerVendor")] + public string xserver_vendor_name (); + + [CCode (cname = "XVendorRelease")] + public string xserver_vendor_release (); + + [CCode (cname = "XMoveWindow")] + public void move_window (Window window, int x, int y); + } + + [Compact] + [CCode (cname = "XModifierKeymap", free_function = "XFreeModifiermap")] + public class ModifierKeymap { + // The server's max # of keys per modifier + public int max_keypermod; + // An 8 by max_keypermod array of modifiers + public uchar[] modifiermap; + } + + [SimpleType] + [IntegerType (rank = 9)] + [CCode (cname = "Atom")] + public struct Atom { + } + + [SimpleType] + [IntegerType (rank = 9)] + [CCode (cname = "Colormap")] + public struct Colormap { + } + + [SimpleType] + [CCode (cname = "GC")] + public struct GC { + } + + [SimpleType] + [IntegerType (rank = 9)] + [CCode (cname = "Status")] + public struct Status { + } + + [SimpleType] + [IntegerType (rank = 9)] + [CCode (cname = "XID", type_id = "G_TYPE_INT", + marshaller_type_name = "INT", + get_value_function = "g_value_get_int", + set_value_function = "g_value_set_int", default_value = "0", + type_signature = "i")] + public struct ID { + } + + [SimpleType] + [IntegerType (rank = 9)] + [CCode (cname = "Drawable", type_id = "G_TYPE_INT", + marshaller_type_name = "INT", + get_value_function = "g_value_get_int", + set_value_function = "g_value_set_int", default_value = "0", + type_signature = "i")] + public struct Drawable : ID + { + } + + [SimpleType] + [IntegerType (rank = 9)] + [CCode (cname = "Window", type_id = "G_TYPE_INT", + marshaller_type_name = "INT", + get_value_function = "g_value_get_int", + set_value_function = "g_value_set_int", default_value = "0", + type_signature = "i")] + public struct Window : Drawable { + } + + + [SimpleType] + [IntegerType (rank = 9)] + [CCode (cname = "Pixmap", type_id = "G_TYPE_INT", + marshaller_type_name = "INT", + get_value_function = "g_value_get_int", + set_value_function = "g_value_set_int", default_value = "0", + type_signature = "i")] + public struct Pixmap : Drawable { + } + + [SimpleType] + [IntegerType (rank = 9)] + [CCode (cname = "Mask")] + public struct Mask { + } + + [SimpleType] + [IntegerType (rank = 9)] + [CCode (cname = "VisualID")] + public struct VisualID { + } + + [SimpleType] + [IntegerType (rank = 9)] + [CCode (cname = "Time")] + public struct Time { + } + + [SimpleType] + [IntegerType (rank = 9)] + [CCode (cname = "Cursor")] + public struct Cursor { + } + + [SimpleType] + [IntegerType (rank = 9)] + [CCode (cname = "GContext")] + public struct GContext { + } + + [SimpleType] + [IntegerType (rank = 9)] + [CCode (cname = "KeySym")] + public struct KeySym { + } + + [SimpleType] + [IntegerType (rank = 9)] + [CCode (cname = "KeyCode")] + public struct KeyCode { + } + + public struct Visual { + } + + public struct WindowChanges { + public int x; + public int y; + public int width; + public int height; + public int border_width; + public Window sibling; + public int stack_mode; + } + public struct SizeHints { + public long @flags; + public int x; + public int y; + public int width; + public int height; + } + + [CCode (cname = "XCreateWindow")] + public Window create_window (Display display, Window parent, int x, int y, uint width, uint height, uint border_width, int depth, uint @class, Visual? visual, X.CW valuemask, ref SetWindowAttributes attributes); + + [CCode (cname = "XSetWindowAttributes")] + public struct SetWindowAttributes { + // public Pixmap background_pixmap; /* background or None or ParentRelative */ + public ulong background_pixel; /* background pixel */ + // public Pixmap border_pixmap; /* border of the window */ + public ulong border_pixel; /* border pixel value */ + public int bit_gravity; /* one of bit gravity values */ + public int win_gravity; /* one of the window gravity values */ + public int backing_store; /* NotUseful, WhenMapped, Always */ + public ulong backing_planes;/* planes to be preseved if possible */ + public ulong backing_pixel;/* value to use in restoring planes */ + public bool save_under; /* should bits under be saved? (popups) */ + public long event_mask; /* set of events that should be saved */ + public long do_not_propagate_mask; /* set of events that should not propagate */ + public bool override_redirect; /* boolean value for override-redirect */ + // public Colormap colormap; /* color map to be associated with window */ + // public Cursor cursor; /* cursor to be displayed (or None) */ + } + + [CCode(cname = "XWindowAttributes", + cheader_filename = "X11/Xlib.h,X11/Xatom.h,X11/Xutil.h")] + public struct WindowAttributes { + public int x; + public int y; /* location of window */ + public int width; + public int height; /* width and height of window */ + public int border_width; /* border width of window */ + public int depth; /* depth of window */ + public Visual visual; /* the associated visual structure */ + public Window root; /* root of screen containing window */ + public int @class; /* InputOutput, InputOnly*/ + public int bit_gravity; /* one of bit gravity values */ + public int win_gravity; /* one of the window gravity values */ + public int backing_store; /* NotUseful, WhenMapped, Always */ + public ulong backing_planes;/* planes to be preserved if possible */ + public ulong backing_pixel;/* value to be used when restoring planes */ + public bool save_under; /* boolean, should bits under be saved? */ + // public Colormap colormap; /* color map to be associated with window */ + public bool map_installed; /* boolean, is color map currently installed*/ + public int map_state; /* IsUnmapped, IsUnviewable, IsViewable */ + public long all_event_masks; /* set of events all people have interest in*/ + public long your_event_mask; /* my event mask */ + public long do_not_propagate_mask; /* set of events that should not propagate */ + public bool override_redirect; /* boolean value for override-redirect */ + // public Screen screen; /* back pointer to correct screen */ + } + + [CCode (cname = "CopyFromParent")] + public const int COPY_FROM_PARENT; + + [CCode (cname = "CurrentTime")] + public const ulong CURRENT_TIME; + + [CCode (cname = "Success")] + public int Success; + + [CCode (cname = "XFree")] + public int free (void* data); + + [CCode (cprefix = "CW", cname = "int")] + public enum CW { + BackPixmap, + BackPixel, + BackingStore, + BackingPlanes, + BackingPixel, + BitGravity, + BorderPixmap, + BorderPixel, + BorderWidth, + Colormap, + Cursor, + DontPropagate, + EventMask, + Height, + OverrideRedirect, + SaveUnder, + Sibling, + StackMode, + X, + Y, + Width, + WinGravity + } + + [CCode (cprefix = "GrabMode")] + public enum GrabMode { + Sync, + Async + } + + [CCode (cprefix = "")] + public enum EventMask { + NoEventMask, + KeyPressMask, + KeyReleaseMask, + ButtonPressMask, + ButtonReleaseMask, + EnterWindowMask, + LeaveWindowMask, + PointerMotionMask, + PointerMotionHintMask, + Button1MotionMask, + Button2MotionMask, + Button3MotionMask, + Button4MotionMask, + Button5MotionMask, + ButtonMotionMask, + KeymapStateMask, + ExposureMask, + VisibilityChangeMask, + StructureNotifyMask, + ResizeRedirectMask, + SubstructureNotifyMask, + SubstructureRedirectMask, + FocusChangeMask, + PropertyChangeMask, + ColormapChangeMask, + OwnerGrabButtonMask + } + + [CCode (cprefix = "")] + public enum KeyMask { + ShiftMask, + LockMask, + ControlMask, + Mod1Mask, + Mod2Mask, + Mod3Mask, + Mod4Mask, + Mod5Mask + } + + [CCode (cprefix = "")] + public enum EventType { + KeyPress, + KeyRelease, + ButtonPress, + ButtonRelease, + MotionNotify, + EnterNotify, + LeaveNotify, + FocusIn, + FocusOut, + KeymapNotify, + Expose, + GraphicsExpose, + NoExpose, + VisibilityNotify, + CreateNotify, + DestroyNotify, + UnmapNotify, + MapNotify, + MapRequest, + ReparentNotify, + ConfigureNotify, + ConfigureRequest, + GravityNotify, + ResizeRequest, + CirculateNotify, + CirculateRequest, + PropertyNotify, + SelectionClear, + SelectionRequest, + SelectionNotify, + ColormapNotify, + ClientMessage, + MappingNotify + } + + // union + [CCode (cname = "XEvent")] + public struct Event { + public int type; + public AnyEvent xany; + public KeyEvent xkey; + public ButtonEvent xbutton; + public MotionEvent xmotion; + public CrossingEvent xcrossing; + public CreateWindowEvent xcreatewindow; + public DestroyWindowEvent xdestroywindow; + public UnmapEvent xunmap; + public MapEvent xmap; + public MapRequestEvent xmaprequest; + public ReparentEvent xreparent; + public ConfigureEvent xconfigure; + public GravityEvent xgravity; + public ConfigureRequestEvent xconfigurerequest; + public CirculateEvent xcirculate; + public CirculateRequestEvent xcirculaterequest; + public PropertyEvent xproperty; + public SelectionEvent xselection; + public ClientMessageEvent xclient; + } + + [CCode (cname = "XAnyEvent")] + public struct AnyEvent { + public int type; + public ulong serial; + public bool send_event; + public unowned Display display; + public Window window; + } + + [CCode (cname = "XKeyEvent")] + public struct KeyEvent { + public int type; + public ulong serial; + public bool send_event; + public unowned Display display; + public Window window; + public Window root; + public Window subwindow; + public ulong time; + public int x; + public int y; + public int x_root; + public int y_root; + public uint state; + public uint keycode; + public bool same_screen; + } + + [CCode (cname = "XButtonEvent")] + public struct ButtonEvent { + public int type; + public ulong serial; + public bool send_event; + public unowned Display display; + public Window window; + public Window subwindow; + public ulong time; + public int x; + public int y; + public int x_root; + public int y_root; + public uint state; + public uint button; + public bool same_screen; + } + + [CCode (cname = "XMotionEvent")] + public struct MotionEvent { + public int type; + public ulong serial; + public bool send_event; + public unowned Display display; + public Window window; + public Window subwindow; + public ulong time; + public int x; + public int y; + public int x_root; + public int y_root; + public uint state; + public char is_hint; + public bool same_screen; + } + + [CCode (cname = "XCrossingEvent")] + public struct CrossingEvent { + public int type; + public ulong serial; + public bool send_event; + public unowned Display display; + public Window window; + public Window root; + public Window subwindow; + public ulong time; + public int x; + public int y; + public int x_root; + public int y_root; + public int mode; + public int detail; + public bool same_screen; + public bool focus; + public uint state; + } + + [CCode (cname = "XCreateWindowEvent")] + public struct CreateWindowEvent { + public int type; + public ulong serial; + public bool send_event; + public unowned Display display; + public Window parent; + public Window window; + public int x; + public int y; + public int width; + public int height; + public int border_width; + public bool override_redirect; + } + + [CCode (cname = "XDestroyWindowEvent")] + public struct DestroyWindowEvent { + public int type; + public ulong serial; + public bool send_event; + public unowned Display display; + public Window event; + public Window window; + } + + [CCode (cname = "XUnmapEvent")] + public struct UnmapEvent { + public int type; + public ulong serial; + public bool send_event; + public unowned Display display; + public Window event; + public Window window; + public bool from_configure; + } + + [CCode (cname = "XMapEvent")] + public struct MapEvent { + public int type; + public ulong serial; + public bool send_event; + public unowned Display display; + public Window event; + public Window window; + public bool override_redirect; + } + + [CCode (cname = "XMapRequestEvent")] + public struct MapRequestEvent { + public int type; + public ulong serial; + public bool send_event; + public unowned Display display; + public Window parent; + public Window window; + } + + [CCode (cname = "XReparentEvent")] + public struct ReparentEvent { + public int type; + public ulong serial; + public bool send_event; + public unowned Display display; + public Window event; + public Window window; + public Window parent; + public int x; + public int y; + public bool override_redirect; + } + + [CCode (cname = "XConfigureEvent")] + public struct ConfigureEvent { + public int type; + public ulong serial; + public bool send_event; + public unowned Display display; + public Window event; + public Window window; + public int x; + public int y; + public int width; + public int height; + public int border_width; + public Window above; + public bool override_redirect; + } + + [CCode (cname = "XGravityEvent")] + public struct GravityEvent { + public int type; + public ulong serial; + public bool send_event; + public unowned Display display; + public Window event; + public Window window; + public int x; + public int y; + } + + [CCode (cname = "XConfigureRequestEvent")] + public struct ConfigureRequestEvent { + public int type; + public ulong serial; + public bool send_event; + public unowned Display display; + public Window parent; + public Window window; + public int x; + public int y; + public int width; + public int height; + public int border_width; + public Window above; + public int detail; + public ulong value_mask; + } + + [CCode (cname = "XCirculateEvent")] + public struct CirculateEvent { + public int type; + public ulong serial; + public bool send_event; + public unowned Display display; + public Window event; + public Window window; + public int place; + } + + [CCode (cname = "XCirculateRequestEvent")] + public struct CirculateRequestEvent { + public int type; + public ulong serial; + public bool send_event; + public unowned Display display; + public Window parent; + public Window window; + public int place; + } + + [CCode (cname = "XPropertyEvent")] + public struct PropertyEvent { + public int type; + public ulong serial; + public bool send_event; + public unowned Display display; + public Window window; + public Atom atom; + public ulong time; + public int state; + } + + [CCode (cname = "XSelectionEvent")] + public struct SelectionEvent { + public int type; + public ulong serial; + public bool send_event; + public unowned Display display; + public Window requestor; + public Atom selection; + public Atom target; + public Atom property; + public ulong time; + } + + [CCode (cname = "XClientMessageEvent")] + public struct ClientMessageEvent { + public int type; + public ulong serial; /* # of last request processed by server */ + public bool send_event; /* true if this came from a SendEvent request */ + public unowned Display display; /* Display the event was read from */ + public Window window; + public Atom message_type; + public int format; + public ClientMessageEventData data; + } + + [CCode (cname = "RECTANGLE", has_type_id = false)] + public struct Rectangle { + public short x; + public short y; + public short width; + public short height; + } + + // union + public struct ClientMessageEventData { + public unowned char[] b; + public unowned short[] s; + public unowned long[] l; + } + + [CCode (cprefix = "Queued")] + public enum QueuedMode { + Already, + AfterFlush, + AfterReading + } + + [CCode (cprefix = "PropMode")] + public enum PropMode { + Replace, + Prepend, + Append + } + + [CCode (cprefix = "")] + public enum AllowEventsMode { + AsyncPointer, + SyncPointer, + ReplayPointer, + AsyncKeyboard, + SyncKeyboard, + ReplayKeyboard, + AsyncBoth, + SyncBoth + } + + [CCode (cprefix = "")] + public enum MapState { + IsUnmapped, + IsUnviewable, + IsViewable + } + + [CCode (cprefix = "RevertTo")] + public enum RevertTo { + None, + PointerRoot, + Parent + } + + [Compact] + [CCode (cname = "Screen")] + public class Screen { + public Display display; + public Window root; + public int width; + public int height; + + [CCode (cname = "XScreenOfDisplay")] + public static unowned Screen get_screen (Display disp, int screen_number); + + [CCode (cname = "XBlackPixelOfScreen")] + public ulong black_pixel_of_screen (); + + [CCode (cname = "XCellsOfScreen")] + public int cells_of_screen (); + + [CCode (cname = "XDefaultColormapOfScreen")] + public Colormap default_colormap_of_screen (); + + [CCode (cname = "XDefaultDepthOfScreen")] + public int default_depth_of_screen (); + + [CCode (cname = "XDefaultGCOfScreen")] + public GC default_gc_of_screen (); + + [CCode (cname = "XDefaultVisualOfScreen")] + public Visual default_visual_of_screen (); + + [CCode (cname = "XDisplayOfScreen")] + public unowned Display display_of_screen (); + + [CCode (cname = "XDoesBackingStore")] + public int does_backing_store (); + + [CCode (cname = "XDoesSaveUnders")] + public bool does_save_unders (); + + [CCode (cname = "XEventMaskOfScreen")] + public long event_mask_of_Screen (); + + [CCode (cname = "XHeightMMOfScreen")] + public int height_in_mm_of_screen (); + + [CCode (cname = "XHeightOfScreen")] + public int height_of_screen (); + + [CCode (cname = "XMaxCmapsOfScreen")] + public int max_colormaps_of_screen (); + + [CCode (cname = "XMinCmapsOfScreen")] + public int min_colormaps_of_screen (); + + [CCode (cname = "XPlanesOfScreen")] + public int planes_of_screen (); + + [CCode (cname = "XRootWindowOfScreen")] + public Window root_window_of_screen (); + + [CCode (cname = "XScreenNumberOfScreen")] + public int screen_number_of_screen (); + + [CCode (cname = "XWhitePixelOfScreen")] + public ulong white_pixel_of_screen (); + + [CCode (cname = "XWidthMMOfScreen")] + public int width_in_mm_of_screen (); + + [CCode (cname = "XWidthOfScreen")] + public int width_of_screen (); + } + + public const X.ID None; + + public const X.Atom XA_ATOM; + public const X.Atom XA_CARDINAL; + public const X.Atom XA_WINDOW; + public const X.Atom XA_WM_CLASS; + public const X.Atom XA_WM_HINTS; + public const X.Atom XA_WM_ICON_NAME; + public const X.Atom XA_WM_NAME; + public const X.Atom XA_WM_NORMAL_HINTS; + public const X.Atom XA_WM_TRANSIENT_FOR; + + public const uint XK_Num_Lock; + public const uint XK_Scroll_Lock; + public const uint XK_Super_L; + public const uint XK_Super_R; +} + diff --git a/vapi/xtst.vapi b/vapi/xtst.vapi new file mode 100644 index 0000000..a773dfa --- /dev/null +++ b/vapi/xtst.vapi @@ -0,0 +1,60 @@ +/* xtst.vapi + * + * Copyright (C) 2011 Alexander Kurtz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: + * Alexander Kurtz + */ + + +[CCode (cprefix = "", lower_case_cprefix = "", cheader_filename = "X11/extensions/XTest.h")] +namespace X { + class Test { + [CCode (cname = "XTestQueryExtension")] + public static bool query_extension(Display display, out int event_base_return, out int error_base_return, out int major_version_return, out int minor_version_return); + + [CCode (cname = "XTestCompareCursorWithWindow")] + public static bool compare_cursor_with_window(Display display, Window window, Cursor cursor); + + [CCode (cname = "XTestCompareCurrentCursorWithWindow")] + public static bool compare_current_cursor_with_window(Display display, Window window); + + [CCode (cname = "XTestFakeKeyEvent")] + public static int fake_key_event(Display display, uint keycode, bool is_press, ulong delay); + + [CCode (cname = "XTestFakeButtonEvent")] + public static int fake_button_event(Display display, uint button, bool is_press, ulong delay); + + [CCode (cname = "XTestFakeMotionEvent")] + public static int fake_motion_event(Display display, int screen_number, int x, int y, ulong delay); + + [CCode (cname = "XTestFakeRelativeMotionEvent")] + public static int fake_relative_motion_event(Display display, int screen_number, int x, int y, ulong delay); + + [CCode (cname = "XTestGrabControl")] + public static int grab_control(Display display, bool impervious); + + [CCode (cname = "XTestSetGContextOfGC")] + public static void set_g_context_of_gc(GC gc, GContext gid); + + [CCode (cname = "XTestSetVisualIDOfVisual")] + public static void set_visual_id_of_visual(Visual visual, VisualID visualid); + + [CCode (cname = "XTestDiscard")] + public static Status discard(Display display); + } +} -- cgit v1.2.3