Merge lp:~audience-members/audience/gtk-3.12 into lp:~audience-members/audience/trunk

Proposed by Corentin Noël
Status: Merged
Approved by: Cody Garver
Approved revision: 355
Merged at revision: 351
Proposed branch: lp:~audience-members/audience/gtk-3.12
Merge into: lp:~audience-members/audience/trunk
Diff against target: 4734 lines (+1792/-2173)
27 files modified
CMakeLists.txt (+3/-59)
cmake/FindGirCompiler.cmake (+56/-0)
cmake/GObjectIntrospectionMacros.cmake (+34/-0)
cmake/Makefile (+0/-286)
cmake/Translations.cmake (+37/-12)
cmake/ValaPrecompile.cmake (+75/-12)
data/CMakeLists.txt (+12/-0)
data/org.pantheon.audience.gschema.xml (+10/-5)
src/Audience.vala (+467/-473)
src/CMakeLists.txt (+57/-0)
src/Consts.vala (+3/-2)
src/DiskManager.vala (+98/-0)
src/Settings.vala (+35/-18)
src/Utils.vala (+56/-202)
src/Widgets/BottomBar.vala (+160/-0)
src/Widgets/Button.vala (+0/-53)
src/Widgets/ControlsBar.vala (+0/-137)
src/Widgets/LLabel.vala (+0/-27)
src/Widgets/MediaSlider.vala (+0/-238)
src/Widgets/Playlist.vala (+92/-57)
src/Widgets/PlaylistPopover.vala (+116/-0)
src/Widgets/PreviewPopover.vala (+90/-0)
src/Widgets/SettingsPopover.vala (+166/-0)
src/Widgets/TagView.vala (+0/-253)
src/Widgets/TimeWidget.vala (+127/-0)
src/Widgets/TopPanel.vala (+0/-87)
src/Widgets/VideoPlayer.vala (+98/-252)
To merge this branch: bzr merge lp:~audience-members/audience/gtk-3.12
Reviewer Review Type Date Requested Status
Cody Garver Needs Fixing
Robert Roth (community) Abstain
Review via email: mp+223919@code.launchpad.net

Commit message

Ported all UI widgets to pure Gtk 3.12

Description of the change

Ported all UI widgets to pure Gtk.

To post a comment you must log in.
348. By Corentin Noël

Synchronized with trunk.

Revision history for this message
Robert Roth (evfool) wrote :

I have tested this branch a few times, felt stable and working. Just for nitpicking: The diff seems a bit hard to read, given that some changes not necessarily related to GTK-3.12 migration have been added (e.g. CMake file splitting per subdir for data and src, generated Makefile removal), those might be better in separate merges, but necessary. If no one else has objections against those being in this one, I'll give this an approve.

review: Abstain
Revision history for this message
David Gomes (davidgomes) wrote :

Agreed with Robert here. Corentin, can you explain us if any of these changes included in this branch (mentioned by Robert) have anything to do with GTK+ 3.12?

Revision history for this message
Corentin Noël (tintou) wrote :

They are not Gtk3.12 related but they are a full part of the project
reorganization (if you look at the changes, a lot of code has been removed).
Le 21 juin 2014 14:45, "David Gomes" <email address hidden> a écrit :

> Agreed with Robert here. Corentin, can you explain us if any of these
> changes included in this branch (mentioned by Robert) have anything to do
> with GTK+ 3.12?
> --
>
> https://code.launchpad.net/~audience-members/audience/gtk-3.12/+merge/223919
> You proposed lp:~audience-members/audience/gtk-3.12 for merging.
>

Revision history for this message
Cody Garver (codygarver) wrote :

- Each video in the playlist is duplicated 01.mkv 01.mkv 02.mkv 02.mkv

- This video doesn't show the controls for me unless I fullscreen then unfullscreen:
  https://slack-files.com/T028SLY6K-F02CDA4MD-c12d7c

- More than 1 video in the playlist requires a scrollbar even if there's available space above

- This video has black bars on the left and right when played windowed:
  https://slack-files.com/T028SLY6K-F02CE461E-df989c

review: Needs Fixing
Revision history for this message
Cody Garver (codygarver) wrote :

Also doesn't properly detect/display the Audio and Subtitle of the video with black bars I linked

review: Needs Fixing
349. By Corentin Noël

Multiple Fixes to the interface.

350. By Corentin Noël

Fix Aspect not replacing the bottombar.

Revision history for this message
Corentin Noël (tintou) wrote :

Cody: I've pushed a fix for the problems you pointed out.

351. By Cody Garver

Add a couple spaces in CMakeLists.txt

352. By Cody Garver

Merge in trunk

Revision history for this message
Cody Garver (codygarver) wrote :

I'm still getting black bars on left/right of this video in windowed mode https://slack-files.com/T028SLY6K-F02CE461E-df989c

review: Needs Fixing
Revision history for this message
Cody Garver (codygarver) wrote :

- Welcome screen does no longer offers to resume last played video

- Welcome screen always offers to play a DVD

review: Needs Fixing
353. By Cody Garver

Restore comment about C warnings

Revision history for this message
Cody Garver (codygarver) wrote :

private void on_destroy () has a block of commented out code

review: Needs Fixing
Revision history for this message
Corentin Noël (tintou) wrote :

I only have black bars on left/right black bars because the video size>screen size. You maybe have an higher resolution as me.

354. By Corentin Noël

Check if the media is a DVD or BlueRay.

355. By Corentin Noël

Fixed saving videos when closing the application.

Revision history for this message
Cody Garver (codygarver) wrote :

Every video has black bars on the side, my display resolution is 1080p

Revision history for this message
Robert Roth (evfool) wrote :

@Cody Garver: Do you get the black bars only in windowed mode? For FullHD movies (e.g. one MKV anime you've shared on slack) for me the black bars only appear in windowed mode, fullscreen is true fullscreen without black bars.

Revision history for this message
Danielle Foré (danrabbit) wrote :

I can confirm that the black bars on the side show up in windowed, but not fullscreen

Revision history for this message
Cody Garver (codygarver) wrote :

Well black bars are happening for me with trunk now too. The problem is outside of this branch?

Revision history for this message
Robert Roth (evfool) wrote :

It looks that the headerbar is the thing to blame on this branch, commenting the set_titlebar line out fixes the issue.
In case of an 1280x720 video the window size is set to 1280x720 (+decorations) in case there is no headerbar, and with headerbar the size is also set to 1280x720, but that includes the CSD size, so the size allocated to the clutterembed is only 1174x572. The headerbar height for me is 42px, so strangely, that's not the only difference.

Revision history for this message
Corentin Noël (tintou) wrote :

For CSD windows, the size also contains shadows so it's maybe linked. In all cases i don't think it's a merge-blocker…

Revision history for this message
Cody Garver (codygarver) wrote :

It is indeed export GTK_CSD=1 that causes the bug, not your fault tintou

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2014-05-02 13:04:44 +0000
+++ CMakeLists.txt 2014-07-06 11:18:29 +0000
@@ -4,7 +4,7 @@
4enable_testing ()4enable_testing ()
5list (APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)5list (APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
66
7project (audience)7project (audience C)
88
9set (DATADIR ${CMAKE_INSTALL_PREFIX}/share)9set (DATADIR ${CMAKE_INSTALL_PREFIX}/share)
10set (PKGDATADIR ${DATADIR}/${CMAKE_PROJECT_NAME})10set (PKGDATADIR ${DATADIR}/${CMAKE_PROJECT_NAME})
@@ -18,17 +18,6 @@
18# Comment this out to enable C compiler warnings18# Comment this out to enable C compiler warnings
19add_definitions (-w)19add_definitions (-w)
2020
21# Data
22install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/icons/16/audience.svg DESTINATION ${DATADIR}/icons/hicolor/16x16/apps/)
23install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/icons/24/audience.svg DESTINATION ${DATADIR}/icons/hicolor/24x24/apps/)
24install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/icons/32/audience.svg DESTINATION ${DATADIR}/icons/hicolor/32x32/apps/)
25install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/icons/48/audience.svg DESTINATION ${DATADIR}/icons/hicolor/48x48/apps/)
26install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/icons/64/audience.svg DESTINATION ${DATADIR}/icons/hicolor/64x64/apps/)
27install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/icons/128/audience.svg DESTINATION ${DATADIR}/icons/hicolor/128x128/apps/)
28install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/audience.desktop DESTINATION ${DATADIR}/applications/)
29
30# Configure file
31configure_file (${CMAKE_SOURCE_DIR}/src/Config.vala.cmake ${CMAKE_BINARY_DIR}/src/Config.vala)
3221
33set (CPACK_PACKAGE_VERSION ${VERSION})22set (CPACK_PACKAGE_VERSION ${VERSION})
34set (CPACK_SOURCE_GENERATOR "TGZ")23set (CPACK_SOURCE_GENERATOR "TGZ")
@@ -38,54 +27,9 @@
38include (CPack)27include (CPack)
39add_custom_target (dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source)28add_custom_target (dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source)
4029
41find_package (PkgConfig)30add_subdirectory (src)
42pkg_check_modules (DEPS REQUIRED granite clutter-gtk-1.0 gstreamer-1.0 gstreamer-pbutils-1.0 gstreamer-tag-1.0)31add_subdirectory (data)
43
44add_definitions (${DEPS_CFLAGS})
45link_libraries (${DEPS_LIBRARIES})
46link_directories (${DEPS_LIBRARY_DIRS})
47find_package (Vala REQUIRED)
48include (ValaVersion)
49
50ensure_vala_version ("0.16.1" MINIMUM)
51
52include (ValaPrecompile)
53vala_precompile (VALA_C
54 ${CMAKE_BINARY_DIR}/src/Config.vala
55 src/Audience.vala
56 src/Consts.vala
57 src/desktop-launcher.vala
58 src/Settings.vala
59 src/Utils.vala
60 src/Widgets/Button.vala
61 src/Widgets/ControlsBar.vala
62 src/Widgets/LLabel.vala
63 src/Widgets/MediaSlider.vala
64 src/Widgets/Playlist.vala
65 src/Widgets/TagView.vala
66 src/Widgets/TopPanel.vala
67 src/Widgets/VideoPlayer.vala
68PACKAGES
69 clutter-gtk-1.0
70 granite
71 gdk-x11-3.0
72 gstreamer-1.0
73 gstreamer-pbutils-1.0
74 gstreamer-tag-1.0
75OPTIONS
76 --enable-experimental
77 --target-glib=2.32
78 --thread
79 -g
80)
81
82
83include (GSettings)
84add_schema ("data/org.pantheon.audience.gschema.xml")
85
86add_subdirectory (po)32add_subdirectory (po)
87add_executable (${CMAKE_PROJECT_NAME} ${VALA_C})
88install (TARGETS ${CMAKE_PROJECT_NAME} RUNTIME DESTINATION bin)
8933
90# uninstall target34# uninstall target
91configure_file (35configure_file (
9236
=== added file 'cmake/FindGirCompiler.cmake'
--- cmake/FindGirCompiler.cmake 1970-01-01 00:00:00 +0000
+++ cmake/FindGirCompiler.cmake 2014-07-06 11:18:29 +0000
@@ -0,0 +1,56 @@
1##
2# Copyright 2009-2010 Jakob Westhoff. All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are met:
6#
7# 1. Redistributions of source code must retain the above copyright notice,
8# this list of conditions and the following disclaimer.
9#
10# 2. Redistributions in binary form must reproduce the above copyright notice,
11# this list of conditions and the following disclaimer in the documentation
12# and/or other materials provided with the distribution.
13#
14# THIS SOFTWARE IS PROVIDED BY JAKOB WESTHOFF ``AS IS'' AND ANY EXPRESS OR
15# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
17# EVENT SHALL JAKOB WESTHOFF OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
18# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
22# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24#
25# The views and conclusions contained in the software and documentation are those
26# of the authors and should not be interpreted as representing official policies,
27# either expressed or implied, of Jakob Westhoff
28##
29
30##
31# Find module for the Gir compiler (g-ir-compiler)
32#
33# This module determines wheter a Gir compiler is installed on the current
34# system and where its executable is.
35#
36# Call the module using "find_package(GirCompiler) from within your CMakeLists.txt.
37#
38# The following variables will be set after an invocation:
39#
40# G_IR_COMPILER_FOUND Whether the g-ir-compiler compiler has been found or not
41# G_IR_COMPILER_EXECUTABLE Full path to the g-ir-compiler executable if it has been found
42##
43
44
45# Search for the g-ir-compiler executable in the usual system paths.
46find_program (G_IR_COMPILER_EXECUTABLE
47 NAMES g-ir-compiler)
48
49# Handle the QUIETLY and REQUIRED arguments, which may be given to the find call.
50# Furthermore set G_IR_COMPILER_FOUND to TRUE if the g-ir-compiler has been found (aka.
51# G_IR_COMPILER_EXECUTABLE is set)
52
53include (FindPackageHandleStandardArgs)
54find_package_handle_standard_args (GirCompiler DEFAULT_MSG G_IR_COMPILER_EXECUTABLE)
55
56mark_as_advanced (G_IR_COMPILER_EXECUTABLE)
057
=== added file 'cmake/GObjectIntrospectionMacros.cmake'
--- cmake/GObjectIntrospectionMacros.cmake 1970-01-01 00:00:00 +0000
+++ cmake/GObjectIntrospectionMacros.cmake 2014-07-06 11:18:29 +0000
@@ -0,0 +1,34 @@
1macro(add_target_gir TARGET_NAME GIR_NAME HEADER CFLAGS GRANITE_VERSION)
2 set(PACKAGES "")
3 foreach(PKG ${ARGN})
4 set(PACKAGES ${PACKAGES} --include=${PKG})
5 endforeach()
6 install(CODE "set(ENV{LD_LIBRARY_PATH} \"${CMAKE_CURRENT_BINARY_DIR}:\$ENV{LD_LIBRARY_PATH}\")
7 execute_process(COMMAND g-ir-scanner ${CFLAGS} -n ${GIR_NAME}
8 --quiet
9 --library ${TARGET_NAME} ${PACKAGES}
10 -o ${CMAKE_CURRENT_BINARY_DIR}/${GIR_NAME}-${GRANITE_VERSION}.gir
11 -L${CMAKE_CURRENT_BINARY_DIR}
12 --nsversion=${GRANITE_VERSION} ${HEADER})")
13 install(CODE "execute_process(COMMAND g-ir-compiler ${CMAKE_CURRENT_BINARY_DIR}/${GIR_NAME}-${GRANITE_VERSION}.gir -o ${CMAKE_CURRENT_BINARY_DIR}/${GIR_NAME}-${GRANITE_VERSION}.typelib)")
14 install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${GIR_NAME}-${GRANITE_VERSION}.gir DESTINATION share/gir-1.0/)
15 install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${GIR_NAME}-${GRANITE_VERSION}.typelib DESTINATION lib/girepository-1.0/)
16endmacro()
17
18macro(add_target_gir_with_executable TARGET_NAME EXE_NAME GIR_NAME HEADER EXE_HEADER CFLAGS GRANITE_VERSION)
19 set(PACKAGES "")
20 foreach(PKG ${ARGN})
21 set(PACKAGES ${PACKAGES} --include=${PKG})
22 endforeach()
23 install(CODE "set(ENV{LD_LIBRARY_PATH} \"${CMAKE_CURRENT_BINARY_DIR}:\$ENV{LD_LIBRARY_PATH}\")
24 execute_process(COMMAND g-ir-scanner ${CFLAGS} -n ${GIR_NAME}
25 --quiet
26 --library ${TARGET_NAME} --program ${EXE_NAME} ${PACKAGES}
27 -o ${CMAKE_CURRENT_BINARY_DIR}/${GIR_NAME}-${GRANITE_VERSION}.gir
28 -L${CMAKE_CURRENT_BINARY_DIR}
29 -I${CMAKE_CURRENT_BINARY_DIR}
30 --nsversion=${GRANITE_VERSION} ${HEADER} ${EXE_HEADER})")
31 install(CODE "execute_process(COMMAND g-ir-compiler ${CMAKE_CURRENT_BINARY_DIR}/${GIR_NAME}-${GRANITE_VERSION}.gir -o ${CMAKE_CURRENT_BINARY_DIR}/${GIR_NAME}-${GRANITE_VERSION}.typelib)")
32 install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${GIR_NAME}-${GRANITE_VERSION}.gir DESTINATION share/gir-1.0/)
33 install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${GIR_NAME}-${GRANITE_VERSION}.typelib DESTINATION lib/girepository-1.0/)
34endmacro()
035
=== removed file 'cmake/Makefile'
--- cmake/Makefile 2011-12-13 18:08:48 +0000
+++ cmake/Makefile 1970-01-01 00:00:00 +0000
@@ -1,286 +0,0 @@
1# CMAKE generated file: DO NOT EDIT!
2# Generated by "Unix Makefiles" Generator, CMake Version 2.8
3
4# Default target executed when no arguments are given to make.
5default_target: all
6.PHONY : default_target
7
8#=============================================================================
9# Special targets provided by cmake.
10
11# Disable implicit rules so canoncical targets will work.
12.SUFFIXES:
13
14# Remove some rules from gmake that .SUFFIXES does not remove.
15SUFFIXES =
16
17.SUFFIXES: .hpux_make_needs_suffix_list
18
19# Suppress display of executed commands.
20$(VERBOSE).SILENT:
21
22# A target that is always out of date.
23cmake_force:
24.PHONY : cmake_force
25
26#=============================================================================
27# Set environment variables for the build.
28
29# The shell in which to execute make rules.
30SHELL = /bin/sh
31
32# The CMake executable.
33CMAKE_COMMAND = /usr/bin/cmake
34
35# The command to remove a file.
36RM = /usr/bin/cmake -E remove -f
37
38# The top-level source directory on which CMake was run.
39CMAKE_SOURCE_DIR = /home/mefrio/Scrivania/cmake
40
41# The top-level build directory on which CMake was run.
42CMAKE_BINARY_DIR = /home/mefrio/Scrivania/cmake/cmake
43
44#=============================================================================
45# Targets provided globally by CMake.
46
47# Special rule for the target edit_cache
48edit_cache:
49 @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running interactive CMake command-line interface..."
50 /usr/bin/cmake -i .
51.PHONY : edit_cache
52
53# Special rule for the target edit_cache
54edit_cache/fast: edit_cache
55.PHONY : edit_cache/fast
56
57# Special rule for the target install
58install: preinstall
59 @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..."
60 /usr/bin/cmake -P cmake_install.cmake
61.PHONY : install
62
63# Special rule for the target install
64install/fast: preinstall/fast
65 @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..."
66 /usr/bin/cmake -P cmake_install.cmake
67.PHONY : install/fast
68
69# Special rule for the target install/local
70install/local: preinstall
71 @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..."
72 /usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake
73.PHONY : install/local
74
75# Special rule for the target install/local
76install/local/fast: install/local
77.PHONY : install/local/fast
78
79# Special rule for the target install/strip
80install/strip: preinstall
81 @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..."
82 /usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake
83.PHONY : install/strip
84
85# Special rule for the target install/strip
86install/strip/fast: install/strip
87.PHONY : install/strip/fast
88
89# Special rule for the target list_install_components
90list_install_components:
91 @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\""
92.PHONY : list_install_components
93
94# Special rule for the target list_install_components
95list_install_components/fast: list_install_components
96.PHONY : list_install_components/fast
97
98# Special rule for the target rebuild_cache
99rebuild_cache:
100 @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..."
101 /usr/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
102.PHONY : rebuild_cache
103
104# Special rule for the target rebuild_cache
105rebuild_cache/fast: rebuild_cache
106.PHONY : rebuild_cache/fast
107
108# The main all target
109all: cmake_check_build_system
110 $(CMAKE_COMMAND) -E cmake_progress_start /home/mefrio/Scrivania/cmake/cmake/CMakeFiles /home/mefrio/Scrivania/cmake/cmake/CMakeFiles/progress.marks
111 $(MAKE) -f CMakeFiles/Makefile2 all
112 $(CMAKE_COMMAND) -E cmake_progress_start /home/mefrio/Scrivania/cmake/cmake/CMakeFiles 0
113.PHONY : all
114
115# The main clean target
116clean:
117 $(MAKE) -f CMakeFiles/Makefile2 clean
118.PHONY : clean
119
120# The main clean target
121clean/fast: clean
122.PHONY : clean/fast
123
124# Prepare targets for installation.
125preinstall: all
126 $(MAKE) -f CMakeFiles/Makefile2 preinstall
127.PHONY : preinstall
128
129# Prepare targets for installation.
130preinstall/fast:
131 $(MAKE) -f CMakeFiles/Makefile2 preinstall
132.PHONY : preinstall/fast
133
134# clear depends
135depend:
136 $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1
137.PHONY : depend
138
139#=============================================================================
140# Target rules for targets named scratch
141
142# Build rule for target.
143scratch: cmake_check_build_system
144 $(MAKE) -f CMakeFiles/Makefile2 scratch
145.PHONY : scratch
146
147# fast build rule for target.
148scratch/fast:
149 $(MAKE) -f CMakeFiles/scratch.dir/build.make CMakeFiles/scratch.dir/build
150.PHONY : scratch/fast
151
152src/entry.o: src/entry.c.o
153.PHONY : src/entry.o
154
155# target to build an object file
156src/entry.c.o:
157 $(MAKE) -f CMakeFiles/scratch.dir/build.make CMakeFiles/scratch.dir/src/entry.c.o
158.PHONY : src/entry.c.o
159
160src/entry.i: src/entry.c.i
161.PHONY : src/entry.i
162
163# target to preprocess a source file
164src/entry.c.i:
165 $(MAKE) -f CMakeFiles/scratch.dir/build.make CMakeFiles/scratch.dir/src/entry.c.i
166.PHONY : src/entry.c.i
167
168src/entry.s: src/entry.c.s
169.PHONY : src/entry.s
170
171# target to generate assembly for a file
172src/entry.c.s:
173 $(MAKE) -f CMakeFiles/scratch.dir/build.make CMakeFiles/scratch.dir/src/entry.c.s
174.PHONY : src/entry.c.s
175
176src/main_window.o: src/main_window.c.o
177.PHONY : src/main_window.o
178
179# target to build an object file
180src/main_window.c.o:
181 $(MAKE) -f CMakeFiles/scratch.dir/build.make CMakeFiles/scratch.dir/src/main_window.c.o
182.PHONY : src/main_window.c.o
183
184src/main_window.i: src/main_window.c.i
185.PHONY : src/main_window.i
186
187# target to preprocess a source file
188src/main_window.c.i:
189 $(MAKE) -f CMakeFiles/scratch.dir/build.make CMakeFiles/scratch.dir/src/main_window.c.i
190.PHONY : src/main_window.c.i
191
192src/main_window.s: src/main_window.c.s
193.PHONY : src/main_window.s
194
195# target to generate assembly for a file
196src/main_window.c.s:
197 $(MAKE) -f CMakeFiles/scratch.dir/build.make CMakeFiles/scratch.dir/src/main_window.c.s
198.PHONY : src/main_window.c.s
199
200src/menu.o: src/menu.c.o
201.PHONY : src/menu.o
202
203# target to build an object file
204src/menu.c.o:
205 $(MAKE) -f CMakeFiles/scratch.dir/build.make CMakeFiles/scratch.dir/src/menu.c.o
206.PHONY : src/menu.c.o
207
208src/menu.i: src/menu.c.i
209.PHONY : src/menu.i
210
211# target to preprocess a source file
212src/menu.c.i:
213 $(MAKE) -f CMakeFiles/scratch.dir/build.make CMakeFiles/scratch.dir/src/menu.c.i
214.PHONY : src/menu.c.i
215
216src/menu.s: src/menu.c.s
217.PHONY : src/menu.s
218
219# target to generate assembly for a file
220src/menu.c.s:
221 $(MAKE) -f CMakeFiles/scratch.dir/build.make CMakeFiles/scratch.dir/src/menu.c.s
222.PHONY : src/menu.c.s
223
224src/notebook.o: src/notebook.c.o
225.PHONY : src/notebook.o
226
227# target to build an object file
228src/notebook.c.o:
229 $(MAKE) -f CMakeFiles/scratch.dir/build.make CMakeFiles/scratch.dir/src/notebook.c.o
230.PHONY : src/notebook.c.o
231
232src/notebook.i: src/notebook.c.i
233.PHONY : src/notebook.i
234
235# target to preprocess a source file
236src/notebook.c.i:
237 $(MAKE) -f CMakeFiles/scratch.dir/build.make CMakeFiles/scratch.dir/src/notebook.c.i
238.PHONY : src/notebook.c.i
239
240src/notebook.s: src/notebook.c.s
241.PHONY : src/notebook.s
242
243# target to generate assembly for a file
244src/notebook.c.s:
245 $(MAKE) -f CMakeFiles/scratch.dir/build.make CMakeFiles/scratch.dir/src/notebook.c.s
246.PHONY : src/notebook.c.s
247
248# Help Target
249help:
250 @echo "The following are some of the valid targets for this Makefile:"
251 @echo "... all (the default if no target is provided)"
252 @echo "... clean"
253 @echo "... depend"
254 @echo "... edit_cache"
255 @echo "... install"
256 @echo "... install/local"
257 @echo "... install/strip"
258 @echo "... list_install_components"
259 @echo "... rebuild_cache"
260 @echo "... scratch"
261 @echo "... src/entry.o"
262 @echo "... src/entry.i"
263 @echo "... src/entry.s"
264 @echo "... src/main_window.o"
265 @echo "... src/main_window.i"
266 @echo "... src/main_window.s"
267 @echo "... src/menu.o"
268 @echo "... src/menu.i"
269 @echo "... src/menu.s"
270 @echo "... src/notebook.o"
271 @echo "... src/notebook.i"
272 @echo "... src/notebook.s"
273.PHONY : help
274
275
276
277#=============================================================================
278# Special targets to cleanup operation of make.
279
280# Special rule to run CMake to check the build system integrity.
281# No rule that depends on this can have commands that come from listfiles
282# because they might be regenerated.
283cmake_check_build_system:
284 $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0
285.PHONY : cmake_check_build_system
286
2870
=== modified file 'cmake/Translations.cmake'
--- cmake/Translations.cmake 2012-06-07 15:38:06 +0000
+++ cmake/Translations.cmake 2014-07-06 11:18:29 +0000
@@ -20,22 +20,47 @@
20 add_custom_target (pot COMMENT “Building translation catalog.”)20 add_custom_target (pot COMMENT “Building translation catalog.”)
21 find_program (XGETTEXT_EXECUTABLE xgettext)21 find_program (XGETTEXT_EXECUTABLE xgettext)
2222
23
24 set(C_SOURCE "")23 set(C_SOURCE "")
24 set(VALA_SOURCE "")
25 set(GLADE_SOURCE "")
2526
26 foreach(FILES_INPUT ${ARGN})27 foreach(FILES_INPUT ${ARGN})
27 file (GLOB SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/${FILES_INPUT}/*.c)28 set(BASE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${FILES_INPUT})
28 foreach(C_FILE ${SOURCE_FILES})29
29 set(C_SOURCE ${C_SOURCE} ${C_FILE})30 file (GLOB_RECURSE SOURCE_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/ ${BASE_DIRECTORY}/*.c)
30 endforeach()31 foreach(C_FILE ${SOURCE_FILES})
31 file (GLOB SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/${FILES_INPUT}/*.vala)32 set(C_SOURCE ${C_SOURCE} ${C_FILE})
32 foreach(C_FILE ${SOURCE_FILES})33 endforeach()
33 set(C_SOURCE ${C_SOURCE} ${C_FILE})34
35 file (GLOB_RECURSE SOURCE_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/ ${BASE_DIRECTORY}/*.vala)
36 foreach(VALA_C_FILE ${SOURCE_FILES})
37 set(VALA_SOURCE ${VALA_SOURCE} ${VALA_C_FILE})
38 endforeach()
39
40 file (GLOB_RECURSE SOURCE_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/ ${BASE_DIRECTORY}/*.ui)
41 foreach(GLADE_C_FILE ${SOURCE_FILES})
42 set(GLADE_SOURCE ${GLADE_SOURCE} ${GLADE_C_FILE})
34 endforeach()43 endforeach()
35 endforeach()44 endforeach()
3645
37 add_custom_command (TARGET pot COMMAND46 set(BASE_XGETTEXT_COMMAND
38 ${XGETTEXT_EXECUTABLE} -d ${NLS_PACKAGE} -o ${CMAKE_CURRENT_SOURCE_DIR}/${NLS_PACKAGE}.pot47 ${XGETTEXT_EXECUTABLE} -d ${NLS_PACKAGE}
39 ${VALA_SOURCE} ${C_SOURCE} --keyword="_" --keyword="N_" --from-code=UTF-848 -o ${CMAKE_CURRENT_SOURCE_DIR}/${NLS_PACKAGE}.pot
40 )49 --add-comments="/" --keyword="_" --keyword="N_" --keyword="C_:1c,2" --keyword="NC_:1c,2" --keyword="ngettext:1,2" --keyword="Q_:1g" --from-code=UTF-8)
50
51 set(CONTINUE_FLAG "")
52
53 IF(NOT "${C_SOURCE}" STREQUAL "")
54 add_custom_command(TARGET pot WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND ${BASE_XGETTEXT_COMMAND} ${C_SOURCE})
55 set(CONTINUE_FLAG "-j")
56 ENDIF()
57
58 IF(NOT "${VALA_SOURCE}" STREQUAL "")
59 add_custom_command(TARGET pot WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND ${BASE_XGETTEXT_COMMAND} ${CONTINUE_FLAG} -LC\# ${VALA_SOURCE})
60 set(CONTINUE_FLAG "-j")
61 ENDIF()
62
63 IF(NOT "${GLADE_SOURCE}" STREQUAL "")
64 add_custom_command (TARGET pot WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND ${BASE_XGETTEXT_COMMAND} ${CONTINUE_FLAG} -LGlade ${GLADE_SOURCE})
65 ENDIF()
41endmacro()66endmacro()
4267
=== modified file 'cmake/ValaPrecompile.cmake'
--- cmake/ValaPrecompile.cmake 2012-02-23 20:42:55 +0000
+++ cmake/ValaPrecompile.cmake 2014-07-06 11:18:29 +0000
@@ -1,5 +1,6 @@
1##1##
2# Copyright 2009-2010 Jakob Westhoff. All rights reserved.2# Copyright 2009-2010 Jakob Westhoff. All rights reserved.
3# Copyright 2012 elementary.
3# 4#
4# Redistribution and use in source and binary forms, with or without5# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are met:6# modification, are permitted provided that the following conditions are met:
@@ -74,10 +75,18 @@
74# be a header file as well as an internal header file being generated called75# be a header file as well as an internal header file being generated called
75# <provided_name>.h and <provided_name>_internal.h76# <provided_name>.h and <provided_name>_internal.h
76#77#
78# GENERATE_GIR
79# Have the compiler generate a GObject-Introspection repository file with
80# name: <provided_name>.gir. This can be later used to create a binary typelib
81# using the GI compiler.
82#
83# GENERATE_SYMBOLS
84# Output a <provided_name>.symbols file containing all the exported symbols.
85#
77# The following call is a simple example to the vala_precompile macro showing86# The following call is a simple example to the vala_precompile macro showing
78# an example to every of the optional sections:87# an example to every of the optional sections:
79#88#
80# vala_precompile(VALA_C89# vala_precompile(VALA_C mytargetname
81# source1.vala90# source1.vala
82# source2.vala91# source2.vala
83# source3.vala92# source3.vala
@@ -95,14 +104,19 @@
95# myvapi104# myvapi
96# GENERATE_HEADER105# GENERATE_HEADER
97# myheader106# myheader
107# GENERATE_GIR
108# mygir
109# GENERATE_SYMBOLS
110# mysymbols
98# )111# )
99#112#
100# Most important is the variable VALA_C which will contain all the generated c113# Most important is the variable VALA_C which will contain all the generated c
101# file names after the call.114# file names after the call.
102##115##
103116
104macro(vala_precompile output)117macro(vala_precompile output target_name)
105 parse_arguments(ARGS "PACKAGES;OPTIONS;DIRECTORY;GENERATE_HEADER;GENERATE_VAPI;CUSTOM_VAPIS" "" ${ARGN})118 parse_arguments(ARGS "TARGET;PACKAGES;OPTIONS;DIRECTORY;GENERATE_GIR;GENERATE_SYMBOLS;GENERATE_HEADER;GENERATE_VAPI;CUSTOM_VAPIS" "" ${ARGN})
119
106 if(ARGS_DIRECTORY)120 if(ARGS_DIRECTORY)
107 set(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${ARGS_DIRECTORY})121 set(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${ARGS_DIRECTORY})
108 else(ARGS_DIRECTORY)122 else(ARGS_DIRECTORY)
@@ -115,15 +129,17 @@
115 endforeach(pkg ${ARGS_PACKAGES})129 endforeach(pkg ${ARGS_PACKAGES})
116 set(in_files "")130 set(in_files "")
117 set(out_files "")131 set(out_files "")
132 set(out_files_display "")
118 set(${output} "")133 set(${output} "")
134
119 foreach(src ${ARGS_DEFAULT_ARGS})135 foreach(src ${ARGS_DEFAULT_ARGS})
120 string(REPLACE ${CMAKE_CURRENT_SOURCE_DIR}/ "" src ${src})
121 string(REGEX MATCH "^/" IS_MATCHED ${src})136 string(REGEX MATCH "^/" IS_MATCHED ${src})
122 if(${IS_MATCHED} MATCHES "/")137 if(${IS_MATCHED} MATCHES "/")
123 list(APPEND in_files "${src}")138 set(src_file_path ${src})
124 else()139 else()
125 list(APPEND in_files "${CMAKE_CURRENT_SOURCE_DIR}/${src}")140 set(src_file_path ${CMAKE_CURRENT_SOURCE_DIR}/${src})
126 endif()141 endif()
142 list(APPEND in_files ${src_file_path})
127 string(REPLACE ".vala" ".c" src ${src})143 string(REPLACE ".vala" ".c" src ${src})
128 string(REPLACE ".gs" ".c" src ${src})144 string(REPLACE ".gs" ".c" src ${src})
129 if(${IS_MATCHED} MATCHES "/")145 if(${IS_MATCHED} MATCHES "/")
@@ -135,6 +151,7 @@
135 list(APPEND out_files "${DIRECTORY}/${src}")151 list(APPEND out_files "${DIRECTORY}/${src}")
136 endif()152 endif()
137 list(APPEND ${output} ${out_file})153 list(APPEND ${output} ${out_file})
154 list(APPEND out_files_display "${src}")
138 endforeach(src ${ARGS_DEFAULT_ARGS})155 endforeach(src ${ARGS_DEFAULT_ARGS})
139156
140 set(custom_vapi_arguments "")157 set(custom_vapi_arguments "")
@@ -151,7 +168,8 @@
151 set(vapi_arguments "")168 set(vapi_arguments "")
152 if(ARGS_GENERATE_VAPI)169 if(ARGS_GENERATE_VAPI)
153 list(APPEND out_files "${DIRECTORY}/${ARGS_GENERATE_VAPI}.vapi")170 list(APPEND out_files "${DIRECTORY}/${ARGS_GENERATE_VAPI}.vapi")
154 set(vapi_arguments "--internal-vapi=${ARGS_GENERATE_VAPI}.vapi")171 list(APPEND out_files_display "${ARGS_GENERATE_VAPI}.vapi")
172 set(vapi_arguments "--library=${ARGS_GENERATE_VAPI}" "--vapi=${ARGS_GENERATE_VAPI}.vapi")
155173
156 # Header and internal header is needed to generate internal vapi174 # Header and internal header is needed to generate internal vapi
157 if (NOT ARGS_GENERATE_HEADER)175 if (NOT ARGS_GENERATE_HEADER)
@@ -162,26 +180,71 @@
162 set(header_arguments "")180 set(header_arguments "")
163 if(ARGS_GENERATE_HEADER)181 if(ARGS_GENERATE_HEADER)
164 list(APPEND out_files "${DIRECTORY}/${ARGS_GENERATE_HEADER}.h")182 list(APPEND out_files "${DIRECTORY}/${ARGS_GENERATE_HEADER}.h")
165 list(APPEND out_files "${DIRECTORY}/${ARGS_GENERATE_HEADER}_internal.h")183 list(APPEND out_files_display "${ARGS_GENERATE_HEADER}.h")
166 list(APPEND header_arguments "--header=${DIRECTORY}/${ARGS_GENERATE_HEADER}.h")184 list(APPEND header_arguments "--header=${ARGS_GENERATE_HEADER}.h")
167 list(APPEND header_arguments "--internal-header=${DIRECTORY}/${ARGS_GENERATE_HEADER}_internal.h")
168 endif(ARGS_GENERATE_HEADER)185 endif(ARGS_GENERATE_HEADER)
169186
170 add_custom_command(OUTPUT ${out_files} 187 set(gir_arguments "")
188 set(gircomp_command "")
189 if(ARGS_GENERATE_GIR)
190 list(APPEND out_files "${DIRECTORY}/${ARGS_GENERATE_GIR}.gir")
191 list(APPEND out_files_display "${ARGS_GENERATE_GIR}.gir")
192 set(gir_arguments "--gir=${ARGS_GENERATE_GIR}.gir")
193
194 include (FindGirCompiler)
195 find_package(GirCompiler REQUIRED)
196
197 set(gircomp_command
198 COMMAND
199 ${G_IR_COMPILER_EXECUTABLE}
200 ARGS
201 "${DIRECTORY}/${ARGS_GENERATE_GIR}.gir"
202 -o "${DIRECTORY}/${ARGS_GENERATE_GIR}.typelib")
203 endif(ARGS_GENERATE_GIR)
204
205 set(symbols_arguments "")
206 if(ARGS_GENERATE_SYMBOLS)
207 list(APPEND out_files "${DIRECTORY}/${ARGS_GENERATE_SYMBOLS}.symbols")
208 list(APPEND out_files_display "${ARGS_GENERATE_SYMBOLS}.symbols")
209 set(symbols_arguments "--symbols=${ARGS_GENERATE_SYMBOLS}.symbols")
210 endif(ARGS_GENERATE_SYMBOLS)
211
212 # Workaround for a bug that would make valac run twice. This file is written
213 # after the vala compiler generates C source code.
214 set(OUTPUT_STAMP ${CMAKE_CURRENT_BINARY_DIR}/${target_name}_valac.stamp)
215
216 add_custom_command(
217 OUTPUT
218 ${OUTPUT_STAMP}
171 COMMAND 219 COMMAND
172 ${VALA_EXECUTABLE} 220 ${VALA_EXECUTABLE}
173 ARGS 221 ARGS
174 "-C" 222 "-C"
175 ${header_arguments} 223 ${header_arguments}
176 ${vapi_arguments}224 ${vapi_arguments}
225 ${gir_arguments}
226 ${symbols_arguments}
177 "-b" ${CMAKE_CURRENT_SOURCE_DIR} 227 "-b" ${CMAKE_CURRENT_SOURCE_DIR}
178 "-d" ${DIRECTORY} 228 "-d" ${DIRECTORY}
179 ${vala_pkg_opts} 229 ${vala_pkg_opts}
180 ${ARGS_OPTIONS} 230 ${ARGS_OPTIONS}
231 "-g"
232 "--save-temps"
181 ${in_files} 233 ${in_files}
182 ${custom_vapi_arguments}234 ${custom_vapi_arguments}
235 COMMAND
236 touch
237 ARGS
238 ${OUTPUT_STAMP}
183 DEPENDS 239 DEPENDS
184 ${in_files} 240 ${in_files}
185 ${ARGS_CUSTOM_VAPIS}241 ${ARGS_CUSTOM_VAPIS}
242 COMMENT
243 "Generating ${out_files_display}"
244 ${gircomp_command}
186 )245 )
246
247 # This command will be run twice for some reason (pass a non-empty string to COMMENT
248 # in order to see it). Since valac is not executed from here, this won't be a problem.
249 add_custom_command(OUTPUT ${out_files} DEPENDS ${OUTPUT_STAMP} COMMENT "")
187endmacro(vala_precompile)250endmacro(vala_precompile)
188251
=== added file 'data/CMakeLists.txt'
--- data/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ data/CMakeLists.txt 2014-07-06 11:18:29 +0000
@@ -0,0 +1,12 @@
1set (HICOLOR_DIR ${DATADIR}/icons/hicolor)
2# Data
3install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/icons/16/audience.svg DESTINATION ${HICOLOR_DIR}/16x16/apps/)
4install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/icons/24/audience.svg DESTINATION ${HICOLOR_DIR}/24x24/apps/)
5install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/icons/32/audience.svg DESTINATION ${HICOLOR_DIR}/32x32/apps/)
6install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/icons/48/audience.svg DESTINATION ${HICOLOR_DIR}/48x48/apps/)
7install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/icons/64/audience.svg DESTINATION ${HICOLOR_DIR}/64x64/apps/)
8install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/icons/128/audience.svg DESTINATION ${HICOLOR_DIR}/128x128/apps/)
9install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/audience.desktop DESTINATION ${DATADIR}/applications/)
10
11include(GSettings)
12add_schema (org.pantheon.audience.gschema.xml)
013
=== modified file 'data/org.pantheon.audience.gschema.xml'
--- data/org.pantheon.audience.gschema.xml 2013-03-31 21:46:37 +0000
+++ data/org.pantheon.audience.gschema.xml 2014-07-06 11:18:29 +0000
@@ -15,10 +15,15 @@
15 <summary>Resume videos</summary>15 <summary>Resume videos</summary>
16 <description>Resume video at the point they were stopped when audience was closed</description>16 <description>Resume video at the point they were stopped when audience was closed</description>
17 </key>17 </key>
18 <key name="last-played-videos" type="s">18 <key name="last-played-videos" type="as">
19 <default>""</default>19 <default>[]</default>
20 <summary>List of last played videos and the time they stopped</summary>20 <summary>List of last played videos</summary>
21 <description>A list of the last played and the time they were stopped</description>21 <description>A list of the last played</description>
22 </key>
23 <key name="last-stopped" type="d">
24 <default>0</default>
25 <summary>Last stopped time of last played video</summary>
26 <description>Last stopped time of last played video</description>
22 </key>27 </key>
23 <key name="last-folder" type="s">28 <key name="last-folder" type="s">
24 <default>"-1"</default>29 <default>"-1"</default>
@@ -41,4 +46,4 @@
41 <description>Hide the window decorations. You can close the window with escape</description>46 <description>Hide the window decorations. You can close the window with escape</description>
42 </key>47 </key>
43 </schema>48 </schema>
44</schemalist>49</schemalist>
45\ No newline at end of file50\ No newline at end of file
4651
=== modified file 'src/Audience.vala'
--- src/Audience.vala 2014-05-25 13:34:00 +0000
+++ src/Audience.vala 2014-07-06 11:18:29 +0000
@@ -1,3 +1,23 @@
1// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
2/*-
3 * Copyright (c) 2013-2014 Audience Developers (http://launchpad.net/pantheon-chat)
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authored by: Tom Beckmann <tomjonabc@gmail.com>
19 * Cody Garver <cody@elementaryos.org>
20 */
121
2/*22/*
3[CCode (cname="gst_navigation_query_parse_commands_length")]23[CCode (cname="gst_navigation_query_parse_commands_length")]
@@ -21,7 +41,7 @@
21 build_version = Constants.VERSION;41 build_version = Constants.VERSION;
22 build_version_info = Constants.VERSION_INFO;42 build_version_info = Constants.VERSION_INFO;
2343
24 app_years = "2011-2013";44 app_years = "2011-2014";
25 app_icon = "audience";45 app_icon = "audience";
26 app_launcher = "audience.desktop";46 app_launcher = "audience.desktop";
27 application_id = "net.launchpad.audience";47 application_id = "net.launchpad.audience";
@@ -40,27 +60,32 @@
40 }60 }
4161
42 public Gtk.Window mainwindow;62 public Gtk.Window mainwindow;
43 public Audience.Widgets.TagView tagview;
44 public GnomeMediaKeys mediakeys;63 public GnomeMediaKeys mediakeys;
45 public Audience.Widgets.Playlist playlist;64 public Audience.Widgets.Playlist playlist;
46 public GtkClutter.Embed clutter;65 public GtkClutter.Embed clutter;
47 public Granite.Widgets.Welcome welcome;66 public Granite.Widgets.Welcome welcome;
48 public Audience.Widgets.VideoPlayer video_player;67
4968 public bool fullscreened { get; set; }
50 public bool has_dvd;69
5170 private Audience.Widgets.VideoPlayer video_player;
52 public List<string> last_played_videos; //taken from settings, but splitted71 private Audience.Widgets.BottomBar bottom_bar;
72 private Clutter.Stage stage;
73 private Gtk.Revealer unfullscreen_bar;
74 private GtkClutter.Actor bottom_actor;
75 private GtkClutter.Actor unfullscreen_actor;
76 private bool mouse_primary_down = false;
77 private int bottom_bar_size = 0;
5378
54 public GLib.VolumeMonitor monitor;79 public GLib.VolumeMonitor monitor;
55 80
56 private const string[] SUBTITLE_EXTENSIONS = {81 private const string[] SUBTITLE_EXTENSIONS = {
57 "sub",82 "sub",
58 "srt",83 "srt",
59 "smi",84 "smi",
60 "ssa",85 "ssa",
61 "ass",86 "ass",
62 "asc"87 "asc"
63 };88 };
6489
65 public App () {90 public App () {
66 Granite.Services.Logger.DisplayLevel = Granite.Services.LogLevel.DEBUG;91 Granite.Services.Logger.DisplayLevel = Granite.Services.LogLevel.DEBUG;
@@ -69,148 +94,77 @@
69 this.flags |= GLib.ApplicationFlags.HANDLES_OPEN;94 this.flags |= GLib.ApplicationFlags.HANDLES_OPEN;
70 }95 }
7196
72 void build ()97 void build () {
73 {
74 playlist = new Widgets.Playlist ();98 playlist = new Widgets.Playlist ();
75 settings = new Settings ();99 settings = new Settings ();
76 mainwindow = new Gtk.Window ();100 mainwindow = new Gtk.Window ();
77 video_player = new Widgets.VideoPlayer ();101 video_player = Widgets.VideoPlayer.get_default ();
78 tagview = new Widgets.TagView (this);102 video_player.notify["playing"].connect (() => {bottom_bar.toggle_play_pause ();});
79103
80 tagview.select_external_subtitle.connect (video_player.set_subtitle_uri);
81
82 var mainbox = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
83 clutter = new GtkClutter.Embed ();104 clutter = new GtkClutter.Embed ();
84105
85 //prepare last played videos
86 last_played_videos = new List<string> ();
87 var split = settings.last_played_videos.split (",");;
88 for (var i=0;i<split.length;i++){
89 last_played_videos.append (split[i]);
90 }
91
92 has_dvd = Audience.has_dvd ();
93
94 if (settings.last_folder == "-1")106 if (settings.last_folder == "-1")
95 settings.last_folder = Environment.get_home_dir ();107 settings.last_folder = Environment.get_home_dir ();
96108
97 welcome = new Granite.Widgets.Welcome (_("No Videos Open"), _("Select a source to begin playing."));109 stage = (Clutter.Stage)clutter.get_stage ();
98 var open_file_welcome_index = welcome.append ("document-open", _("Open file"), _("Open a saved file."));110 stage.background_color = {0, 0, 0, 0};
99111 stage.use_alpha = true;
100 var filename = last_played_videos.length () > 0 ? last_played_videos.nth_data (0) : "";
101 var last_file = File.new_for_uri (filename);
102
103 var last_video_welcome_index = -1;
104 if (last_file.query_exists ()) {
105 last_video_welcome_index = welcome.append ("media-playback-start", _("Resume last video"), get_title (last_file.get_basename ()));
106 welcome.set_item_visible (last_video_welcome_index, last_played_videos.length () > 0);
107 }
108
109 var dvd_welcome_index = welcome.append ("media-cdrom", _("Play from Disc"), _("Watch a DVD or open a file from disc"));
110 welcome.set_item_visible (dvd_welcome_index, has_dvd);
111
112 var stage = clutter.get_stage ();
113112
114 video_player.add_constraint (new Clutter.BindConstraint (stage, Clutter.BindCoordinate.WIDTH, 0));113 video_player.add_constraint (new Clutter.BindConstraint (stage, Clutter.BindCoordinate.WIDTH, 0));
115 video_player.add_constraint (new Clutter.BindConstraint (stage, Clutter.BindCoordinate.HEIGHT, 0));114 video_player.add_constraint (new Clutter.BindConstraint (stage, Clutter.BindCoordinate.HEIGHT, 0));
116115
117 stage.add_child (video_player);116 stage.add_child (video_player);
118 stage.add_child (tagview);117
119 stage.background_color = {0, 0, 0};118 bottom_bar = new Widgets.BottomBar ();
120119 bottom_bar.set_valign (Gtk.Align.END);
121 this.tagview.y = -10;120 bottom_bar.play_toggled.connect (() => {video_player.playing = !video_player.playing;});
122 this.tagview.x = stage.width;121 bottom_bar.seeked.connect ((val) => {video_player.progress = val;});
123 this.tagview.add_constraint (new Clutter.BindConstraint (stage, Clutter.BindCoordinate.HEIGHT, -20));122 bottom_bar.unfullscreen.connect (() => {toggle_fullscreen ();});
124123
124 //tagview.select_external_subtitle.connect (video_player.set_subtitle_uri);
125
126 unfullscreen_bar = bottom_bar.get_unfullscreen_button ();
127
128 bottom_actor = new GtkClutter.Actor.with_contents (bottom_bar);
129 bottom_actor.opacity = GLOBAL_OPACITY;
130 stage.add_child (bottom_actor);
131
132 unfullscreen_actor = new GtkClutter.Actor.with_contents (unfullscreen_bar);
133 unfullscreen_actor.opacity = GLOBAL_OPACITY;
134 stage.add_child (unfullscreen_actor);
135
136 setup_welcome_screen ();
137
138 var mainbox = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
139 mainbox.pack_start (clutter);
125 mainbox.pack_start (welcome);140 mainbox.pack_start (welcome);
126 mainbox.pack_start (clutter);141
127142 var header = new Gtk.HeaderBar ();
128 this.mainwindow.title = program_name;143 header.set_show_close_button (true);
129 this.mainwindow.window_position = Gtk.WindowPosition.CENTER;144 header.get_style_context ().remove_class ("header-bar");
130 this.mainwindow.set_application (this);145
131 this.mainwindow.add (mainbox);146 mainwindow.set_titlebar (header);
132 this.mainwindow.set_default_size (624, 352);147
133 this.mainwindow.show_all ();148 mainwindow.events |= Gdk.EventMask.POINTER_MOTION_MASK;
149 mainwindow.events |= Gdk.EventMask.LEAVE_NOTIFY_MASK;
150 mainwindow.events |= Gdk.EventMask.BUTTON_PRESS_MASK;
151 mainwindow.title = program_name;
152 mainwindow.window_position = Gtk.WindowPosition.CENTER;
153 mainwindow.set_application (this);
154 mainwindow.add (mainbox);
155 mainwindow.set_default_size (624, 352);
156 mainwindow.set_size_request (350, 300);
157 mainwindow.show_all ();
134 if (!settings.show_window_decoration)158 if (!settings.show_window_decoration)
135 this.mainwindow.decorated = false;159 mainwindow.decorated = false;
136160
137 clutter.hide ();161 clutter.hide ();
138162
139 /*events*/
140 video_player.text_tags_changed.connect (tagview.setup_text_setup);
141 video_player.audio_tags_changed.connect (tagview.setup_audio_setup);
142
143 //look for dvd
144 this.monitor = GLib.VolumeMonitor.get ();
145 monitor.drive_connected.connect ( (drive) => {
146 this.has_dvd = Audience.has_dvd ();
147 welcome.set_item_visible (dvd_welcome_index, this.has_dvd);
148 });
149 monitor.drive_disconnected.connect ( () => {
150 this.has_dvd = Audience.has_dvd ();
151 welcome.set_item_visible (dvd_welcome_index, this.has_dvd);
152 });
153 //playlist wants us to open a file
154 playlist.play.connect ( (file) => {
155 this.play_file (file.get_uri ());
156 });
157
158 //handle welcome
159 welcome.activated.connect ( (index) => {
160 if (index == open_file_welcome_index) {
161 run_open_file ();
162 } else if (index == last_video_welcome_index) {
163 welcome.hide ();
164 clutter.show_all ();
165
166 open_file (filename);
167
168 video_player.playing = false;
169 video_player.progress = double.parse (last_played_videos.nth_data (1));
170 video_player.playing = true;
171 } else if (index == dvd_welcome_index) {
172 run_open_dvd ();
173 } else {
174 var d = new Gtk.Dialog.with_buttons (_("Open location"),
175 this.mainwindow, Gtk.DialogFlags.MODAL,
176 Gtk.Stock.CANCEL, Gtk.ResponseType.CANCEL,
177 Gtk.Stock.OK, Gtk.ResponseType.OK);
178
179 var grid = new Gtk.Grid ();
180 var entry = new Gtk.Entry ();
181
182 grid.attach (new Gtk.Image.from_icon_name ("internet-web-browser",
183 Gtk.IconSize.DIALOG), 0, 0, 1, 2);
184 grid.attach (new Gtk.Label (_("Choose location")), 1, 0, 1, 1);
185 grid.attach (entry, 1, 1, 1, 1);
186
187 ((Gtk.Container)d.get_content_area ()).add (grid);
188 grid.show_all ();
189
190 if (d.run () == Gtk.ResponseType.OK) {
191 open_file (entry.text, true);
192 video_player.playing = true;
193 welcome.hide ();
194 clutter.show_all ();
195 }
196 d.destroy ();
197 }
198
199 int current_state = mainwindow.get_window ().get_state ();
200 bool currently_maximized = (current_state & Gdk.WindowState.MAXIMIZED) != 0;
201
202 // video is playing and we are maximized, go fullscreen
203 if (video_player.playing && currently_maximized) {
204 mainwindow.fullscreen ();
205 video_player.fullscreened = true;
206 }
207 });
208
209 //media keys163 //media keys
210 try {164 try {
211 mediakeys = Bus.get_proxy_sync (BusType.SESSION,165 mediakeys = Bus.get_proxy_sync (BusType.SESSION,
212 "org.gnome.SettingsDaemon", "/org/gnome/SettingsDaemon/MediaKeys");166 "org.gnome.SettingsDaemon", "/org/gnome/SettingsDaemon/MediaKeys");
213 mediakeys.MediaPlayerKeyPressed.connect ( (bus, app, key) => {167 mediakeys.MediaPlayerKeyPressed.connect ((bus, app, key) => {
214 if (app != "audience")168 if (app != "audience")
215 return;169 return;
216 switch (key) {170 switch (key) {
@@ -229,138 +183,25 @@
229 });183 });
230184
231 mediakeys.GrabMediaPlayerKeys("audience", 0);185 mediakeys.GrabMediaPlayerKeys("audience", 0);
232 } catch (Error e) { warning (e.message); }186 } catch (Error e) {
233187 warning (e.message);
234 //shortcuts188 }
235 this.mainwindow.key_press_event.connect ( (e) => {189
236 switch (e.keyval) {190 /*events*/
237 case Gdk.Key.p:191 video_player.text_tags_changed.connect (bottom_bar.preferences_popover.setup_text);
238 case Gdk.Key.space:192 video_player.audio_tags_changed.connect (bottom_bar.preferences_popover.setup_audio);
239 video_player.playing = !video_player.playing;193 video_player.progression_changed.connect ((current_time, total_time) => {
240 break;194 bottom_bar.set_progression_time (current_time, total_time);
241 case Gdk.Key.Escape:
242 if (video_player.fullscreened)
243 toggle_fullscreen ();
244 else
245 mainwindow.destroy ();
246 break;
247 case Gdk.Key.o:
248 run_open_file ();
249 break;
250 case Gdk.Key.f:
251 case Gdk.Key.F11:
252 toggle_fullscreen ();
253 break;
254 case Gdk.Key.q:
255 mainwindow.destroy ();
256 break;
257 case Gdk.Key.Left:
258 if ((video_player.progress - 0.05) < 0)
259 video_player.progress = 0.0;
260 else
261 video_player.progress -= 0.05;
262 break;
263 case Gdk.Key.Right:
264 video_player.progress += 0.05;
265 break;
266 case Gdk.Key.a:
267 next_audio ();
268 break;
269 case Gdk.Key.s:
270 next_text ();
271 break;
272 default:
273 break;
274 }
275
276 return true;
277 });195 });
278196
279 //end197 //end
280 video_player.ended.connect ( () => {198 video_player.ended.connect (() => {
281 Idle.add (()=>{199 Idle.add (() => {
282 playlist.next ();200 playlist.next ();
283 return false;201 return false;
284 });202 });
285 });203 });
286204
287 /*open location popover*/
288 video_player.show_open_context.connect ( () => {
289 var has_been_stopped = video_player.playing;
290
291 video_player.playing = false;
292
293 if (!has_dvd) { //just one source, so open that one
294 Timeout.add (300, () => {
295 run_open_file ();
296 return false;
297 });
298 return;
299 }
300
301 var pop = new Granite.Widgets.PopOver ();
302 var box = new Gtk.Box (Gtk.Orientation.VERTICAL, 6);
303 ((Gtk.Box)pop.get_content_area ()).add (box);
304
305 var fil = new Gtk.Button.with_label (_("Add from Harddrive"));
306 fil.image = new Gtk.Image.from_icon_name ("document-open", Gtk.IconSize.DIALOG);
307 var dvd = new Gtk.Button.with_label (_("Play a DVD"));
308 dvd.image = new Gtk.Image.from_icon_name ("media-cdrom", Gtk.IconSize.DIALOG);
309 var net = new Gtk.Button.with_label (_("Network File"));
310 net.image = new Gtk.Image.from_icon_name ("internet-web-browser", Gtk.IconSize.DIALOG);
311
312 fil.clicked.connect ( () => {
313 pop.destroy ();
314 run_open_file ();
315 });
316 dvd.clicked.connect ( () => {
317 run_open_dvd ();
318 pop.destroy ();
319 });
320 net.clicked.connect ( () => {
321 var entry = new Gtk.Entry ();
322 entry.secondary_icon_stock = Gtk.Stock.OPEN;
323 entry.icon_release.connect ( (pos, e) => {
324 open_file (entry.text);
325 video_player.playing = true;
326 pop.destroy ();
327 });
328 box.remove (net);
329 box.reorder_child (entry, 2);
330 entry.show ();
331 });
332
333 box.pack_start (fil);
334 if (has_dvd)
335 box.pack_start (dvd);
336 //box.pack_start (net); uri temporary dropped
337
338 /*temporary until popover closing gets fixed*/
339 var canc = new Gtk.Button.from_stock (Gtk.Stock.CANCEL);
340 box.pack_start (canc);
341 canc.clicked.connect ( () => {
342 pop.destroy ();
343 });
344
345 int x_r, y_r;
346 this.mainwindow.get_window ().get_origin (out x_r, out y_r);
347
348 pop.move_to_coords ((int)(x_r + clutter.get_stage ().width - 50),
349 (int)(y_r + stage.height - 18));
350
351 pop.show_all ();
352
353 Timeout.add (300, () => { //for some reason this doesn't cause a crash :)
354 pop.present ();
355 pop.run ();
356 pop.destroy ();
357 if (has_been_stopped)
358 video_player.playing = true;
359
360 return false;
361 });
362 });
363
364 video_player.error.connect (() => {205 video_player.error.connect (() => {
365 welcome.show_all ();206 welcome.show_all ();
366 clutter.hide ();207 clutter.hide ();
@@ -375,196 +216,347 @@
375 mainwindow.set_keep_above (video_player.playing && settings.stay_on_top);216 mainwindow.set_keep_above (video_player.playing && settings.stay_on_top);
376 });217 });
377218
378 video_player.exit_fullscreen.connect (toggle_fullscreen);219 notify["fullscreened"].connect (() => {bottom_bar.fullscreen = fullscreened;});
379220
380 video_player.toggle_side_pane.connect ((show) => {221 setup_drag_n_drop ();
381 if (show) {222 video_player.configure_window.connect ((video_w, video_h) => {on_configure_window (video_w, video_h);});
382 tagview.expand ();223
383 } else {224 //fullscreen on maximize
384 tagview.collapse ();225 mainwindow.window_state_event.connect ((e) => {
385 }226 on_window_state_changed (e.window.get_state ());
386 });227 return false;
387228 });
388 video_player.configure_window.connect ((video_w, video_h) => {229
389230 mainwindow.size_allocate.connect ((alloc) => {on_size_allocate (alloc);});
390 Gdk.Rectangle monitor;231 mainwindow.motion_notify_event.connect ((event) => {
391 var screen = Gdk.Screen.get_default ();232 if (event.window == null)
392 screen.get_monitor_geometry (233 return false;
393 screen.get_monitor_at_window (mainwindow.get_window ()),234
394 out monitor);235 if (mouse_primary_down && settings.move_window) {
395236 mouse_primary_down = false;
396 int width = 0, height = 0;237 mainwindow.begin_move_drag (Gdk.BUTTON_PRIMARY,
397 if (monitor.width > video_w && monitor.height > video_h) {238 (int)event.x_root, (int)event.y_root, event.time);
398 width = (int)video_w;239 }
399 height = (int)video_h;240
400 } else {241 Gtk.Allocation allocation;
401 width = (int)(monitor.width * 0.9);242 clutter.get_allocation (out allocation);
402 height = (int)((double)video_h / video_w * width);243 return update_pointer_position (event.y, allocation.height);
403 }244 });
404245
246 bottom_bar.time_widget.slider_motion_event.connect ((event) => {
247 int x, y;
248 bottom_bar.translate_coordinates (mainwindow, (int)event.x, (int)event.y, out x, out y);
249 Gtk.Allocation allocation;
250 clutter.get_allocation (out allocation);
251 update_pointer_position (y, allocation.height);
252 });
253
254 mainwindow.button_press_event.connect ((event) => {
255 if (event.type == Gdk.EventType.2BUTTON_PRESS) {
256 toggle_fullscreen ();
257 }
258
259 if (event.button == Gdk.BUTTON_PRIMARY)
260 mouse_primary_down = true;
261
262 return false;
263 });
264
265 mainwindow.button_release_event.connect ((event) => {
266 if (event.button == Gdk.BUTTON_PRIMARY)
267 mouse_primary_down = false;
268
269 return false;
270 });
271
272 mainwindow.leave_notify_event.connect ((event) => {
273 if (event.window == null)
274 return false;
275
276 Gtk.Allocation allocation;
277 clutter.get_allocation (out allocation);
278 if (event.x == event.window.get_width ())
279 return update_pointer_position (event.window.get_height (), allocation.height);
280 else if (event.x == 0)
281 return update_pointer_position (event.window.get_height (), allocation.height);
282 return update_pointer_position (event.y, allocation.height);
283 });
284 //shortcuts
285 this.mainwindow.key_press_event.connect ((e) => {
286 return on_key_press_event (e);
287 });
288
289 //save position in video when not finished playing
290 mainwindow.destroy.connect (() => {on_destroy ();});
291
292 //playlist wants us to open a file
293 playlist.play.connect ((file) => {
294 this.play_file (file.get_uri ());
295 });
296
297 bottom_bar.notify["child-revealed"].connect (() => {
298 if (bottom_bar.child_revealed == true) {
299 mainwindow.get_window ().set_cursor (null);
300 } else {
301 mainwindow.get_window ().set_cursor (new Gdk.Cursor (Gdk.CursorType.BLANK_CURSOR));
302 }
303 });
304
305 stage.notify["allocation"].connect (() => {allocate_bottombar ();});
306
307 if (settings.resume_videos == true && settings.last_played_videos.length > 0) {
308 welcome.hide ();
309 clutter.show_all ();
310 foreach (var filename in settings.last_played_videos) {
311 open_file (filename);
312 }
313
314 video_player.playing = false;
315 video_player.progress = settings.last_stopped;
316 video_player.playing = true;
317 }
318 }
319
320 private void allocate_bottombar () {
321 bottom_actor.width = stage.get_width ();
322 bottom_bar.queue_resize ();
323 bottom_actor.y = stage.get_height () - bottom_bar_size;
324 unfullscreen_actor.y = 6;
325 unfullscreen_actor.x = stage.get_width () - bottom_bar_size - 6;
326 }
327
328 private void setup_welcome_screen () {
329 welcome = new Granite.Widgets.Welcome (_("No Videos Open"), _("Select a source to begin playing."));
330 welcome.append ("document-open", _("Open file"), _("Open a saved file."));
331
332 //welcome.append ("internet-web-browser", _("Open a location"), _("Watch something from the infinity of the internet"));
333 var filename = settings.last_played_videos.length > 0 ? settings.last_played_videos[0] : "";
334 var last_file = File.new_for_path (filename);
335 welcome.append ("media-playback-start", _("Resume last video"), get_title (last_file.get_basename ()));
336 bool show_last_file = settings.last_played_videos.length > 0;
337 if (last_file.query_exists () == false) {
338 show_last_file = false;
339 }
340
341 welcome.set_item_visible (1, show_last_file);
342
343 welcome.append ("media-cdrom", _("Play from Disc"), _("Watch a DVD or open a file from disc"));
344 welcome.set_item_visible (2, false);
345
346 //look for dvd
347 var disk_manager = DiskManager.get_default ();
348 foreach (var volume in disk_manager.get_volumes ()) {
349 welcome.set_item_visible (2, true);
350 }
351
352 disk_manager.volume_found.connect ((vol) => {
353 welcome.set_item_visible (2, true);
354 });
355
356 disk_manager.volume_removed.connect ((vol) => {
357 if (disk_manager.get_volumes ().length () <= 0)
358 welcome.set_item_visible (2, false);
359 });
360
361 //handle welcome
362 welcome.activated.connect ((index) => {
363 switch (index) {
364 case 0:
365 run_open_file ();
366 break;
367 case 1:
368 welcome.hide ();
369 clutter.show_all ();
370 open_file (filename);
371 video_player.playing = false;
372 video_player.progress = settings.last_stopped;
373 video_player.playing = true;
374 break;
375 case 2:
376 run_open_dvd ();
377 break;
378 default:
379 var d = new Gtk.Dialog.with_buttons (_("Open location"),
380 this.mainwindow, Gtk.DialogFlags.MODAL,
381 _("Cancel"), Gtk.ResponseType.CANCEL,
382 _("OK"), Gtk.ResponseType.OK);
383
384 var grid = new Gtk.Grid ();
385 var entry = new Gtk.Entry ();
386
387 grid.attach (new Gtk.Image.from_icon_name ("internet-web-browser",
388 Gtk.IconSize.DIALOG), 0, 0, 1, 2);
389 grid.attach (new Gtk.Label (_("Choose location")), 1, 0, 1, 1);
390 grid.attach (entry, 1, 1, 1, 1);
391
392 ((Gtk.Container)d.get_content_area ()).add (grid);
393 grid.show_all ();
394
395 if (d.run () == Gtk.ResponseType.OK) {
396 open_file (entry.text, true);
397 video_player.playing = true;
398 welcome.hide ();
399 clutter.show_all ();
400 }
401
402 d.destroy ();
403 break;
404 }
405
406 int current_state = mainwindow.get_window ().get_state ();
407 bool currently_maximized = (current_state & Gdk.WindowState.MAXIMIZED) != 0;
408
409 // video is playing and we are maximized, go fullscreen
410 if (video_player.playing && currently_maximized) {
411 mainwindow.fullscreen ();
412 fullscreened = true;
413 }
414 });
415 }
416
417 private bool on_key_press_event (Gdk.EventKey e) {
418 switch (e.keyval) {
419 case Gdk.Key.p:
420 case Gdk.Key.space:
421 video_player.playing = !video_player.playing;
422 break;
423 case Gdk.Key.Escape:
424 if (fullscreened)
425 toggle_fullscreen ();
426 else
427 mainwindow.destroy ();
428 break;
429 case Gdk.Key.o:
430 run_open_file ();
431 break;
432 case Gdk.Key.f:
433 case Gdk.Key.F11:
434 toggle_fullscreen ();
435 break;
436 case Gdk.Key.q:
437 mainwindow.destroy ();
438 break;
439 case Gdk.Key.Left:
440 if ((video_player.progress - 0.05) < 0)
441 video_player.progress = 0.0;
442 else
443 video_player.progress -= 0.05;
444 break;
445 case Gdk.Key.Right:
446 video_player.progress += 0.05;
447 break;
448 case Gdk.Key.a:
449 bottom_bar.preferences_popover.next_audio ();
450 break;
451 case Gdk.Key.s:
452 bottom_bar.preferences_popover.next_text ();
453 break;
454 default:
455 break;
456 }
457
458 return true;
459 }
460
461 private void on_configure_window (uint video_w, uint video_h) {
462 Gdk.Rectangle monitor;
463 var screen = Gdk.Screen.get_default ();
464 screen.get_monitor_geometry (screen.get_monitor_at_window (mainwindow.get_window ()), out monitor);
465
466 int width = 0, height = 0;
467 if (monitor.width > video_w && monitor.height > video_h) {
468 width = (int)video_w;
469 height = (int)video_h;
470 } else {
471 width = (int)(monitor.width * 0.9);
472 height = (int)((double)video_h / video_w * width);
473 }
474
475 mainwindow.get_window ().move_resize (monitor.width / 2 - width / 2 + monitor.x,
476 monitor.height / 2 - height / 2 + monitor.y,
477 width, height);
478
479 if (settings.keep_aspect) {
405 var geom = Gdk.Geometry ();480 var geom = Gdk.Geometry ();
406 if (settings.keep_aspect) {481 geom.min_aspect = geom.max_aspect = video_w / (double)video_h;
407 geom.min_aspect = geom.max_aspect = video_w / (double)video_h;482 mainwindow.get_window ().set_geometry_hints (geom, Gdk.WindowHints.ASPECT);
408 } else {483 }
409 geom.min_aspect = 0.0;484 }
410 geom.max_aspect = 99999999.0;485
411 }486 private void on_window_state_changed (Gdk.WindowState window_state) {
412487 bool currently_maximized = (window_state & Gdk.WindowState.MAXIMIZED) == 0;
413 mainwindow.get_window ().move_resize (monitor.width / 2 - width / 2 + monitor.x,488
414 monitor.height / 2 - height / 2 + monitor.y,489 if (!currently_maximized && !fullscreened && !welcome.is_visible ()) {
415 width, height);490 mainwindow.fullscreen ();
416491 fullscreened = true;
417 if (settings.keep_aspect) {492 }
418 mainwindow.get_window ().set_geometry_hints (geom, Gdk.WindowHints.ASPECT);493 }
419 }494
420495 /*DnD*/
421 });496 private void setup_drag_n_drop () {
422
423 //fullscreen on maximize
424 mainwindow.window_state_event.connect ( (e) => {
425 bool currently_maximized = (e.window.get_state () & Gdk.WindowState.MAXIMIZED) == 0;
426
427 if (!currently_maximized && !video_player.fullscreened && !welcome.is_visible ()) {
428 mainwindow.fullscreen ();
429 video_player.fullscreened = true;
430
431 return true;
432 }
433 return false;
434 });
435
436 //positioning
437 int old_h = - 1;
438 int old_w = - 1;
439 mainwindow.size_allocate.connect ( (alloc) => {
440 if (alloc.width != old_w ||
441 alloc.height != old_h) {
442 if (video_player.relayout ()) {
443 old_w = alloc.width;
444 old_h = alloc.height;
445 }
446 }
447
448 tagview.x = tagview.expanded ? stage.width - tagview.width + 10 : stage.width;
449 });
450
451 /*moving the window by drag, fullscreen for dbl-click*/
452 bool down = false;
453 bool moving = false;
454 video_player.button_press_event.connect ( (e) => {
455 if (e.click_count > 1) {
456 toggle_fullscreen ();
457 down = false;
458 return true;
459 } else {
460 down = true;
461 return true;
462 }
463 });
464 clutter.motion_notify_event.connect ( (e) => {
465 if (down && settings.move_window) {
466 down = false;
467 moving = true;
468 mainwindow.begin_move_drag (1,
469 (int)e.x_root, (int)e.y_root, e.time);
470
471 video_player.lock_hide ();
472
473 return true;
474 }
475 return false;
476 });
477 clutter.button_release_event.connect ( (e) => {
478 down = false;
479 return false;
480 });
481 mainwindow.focus_in_event.connect (() => {
482 if (moving) {
483 video_player.unlock_hide ();
484 moving = false;
485 }
486 return false;
487 });
488
489 /*DnD*/
490 Gtk.TargetEntry uris = {"text/uri-list", 0, 0};497 Gtk.TargetEntry uris = {"text/uri-list", 0, 0};
491 Gtk.drag_dest_set (mainwindow, Gtk.DestDefaults.ALL, {uris}, Gdk.DragAction.MOVE);498 Gtk.drag_dest_set (mainwindow, Gtk.DestDefaults.ALL, {uris}, Gdk.DragAction.MOVE);
492 mainwindow.drag_data_received.connect ( (ctx, x, y, sel, info, time) => {499 mainwindow.drag_data_received.connect ( (ctx, x, y, sel, info, time) => {
493 for (var i=1;i<sel.get_uris ().length; i++)500 foreach (var uri in sel.get_uris ()) {
494 playlist.add_item (File.new_for_uri (sel.get_uris ()[i]));501 playlist.add_item (File.new_for_uri (uri));
502 }
495 open_file (sel.get_uris ()[0]);503 open_file (sel.get_uris ()[0]);
496
497 welcome.hide ();504 welcome.hide ();
498 clutter.show_all ();505 clutter.show_all ();
499 });506 });
500507 }
501 //save position in video when not finished playing508
502 mainwindow.destroy.connect ( () => {509 private void on_destroy () {
503 if (video_player.uri == null || video_player.uri == "" || video_player.uri.has_prefix ("dvd://"))510 if (video_player.uri == null || video_player.uri == "" || video_player.uri.has_prefix ("dvd://"))
504 return;511 return;
505 if (!video_player.at_end) {512 if (!video_player.at_end) {
506 for (var i = 0; i < last_played_videos.length (); i += 2){513 save_last_played_videos ();
507 if (video_player.uri == last_played_videos.nth_data (i)){514 }
508 last_played_videos.nth (i+1).data = video_player.progress.to_string ();515 }
509 save_last_played_videos ();516
510517 private int old_h = - 1;
511 return;518 private int old_w = - 1;
512 }519 private void on_size_allocate (Gtk.Allocation alloc) {
513 }520 if (alloc.width != old_w || alloc.height != old_h) {
514 //not in list yet, insert at start521 if (video_player.relayout ()) {
515 last_played_videos.insert (video_player.uri, 0);522 old_w = alloc.width;
516 last_played_videos.insert (video_player.progress.to_string (), 1);523 old_h = alloc.height;
517 if (last_played_videos.length () > 10) {524 }
518 last_played_videos.delete_link (last_played_videos.nth (10));525 }
519 last_played_videos.delete_link (last_played_videos.nth (11));526 }
520 }527
521 save_last_played_videos ();528 private bool update_pointer_position (double y, int window_height) {
522 }529 allocate_bottombar ();
523 });530 mainwindow.get_window ().set_cursor (null);
524 }531 if (bottom_bar_size == 0) {
525532 int minimum = 0;
526 public void next_audio () {533 bottom_bar.get_preferred_height (out minimum, out bottom_bar_size);
527 int n_audio;534 }
528 video_player.playbin.get ("n-audio", out n_audio);535
529 int current = video_player.current_audio;536 if (bottom_bar.child_revealed == false)
530537 bottom_bar.set_reveal_child (true);
531 if (n_audio > 1) {538
532 if (current < n_audio - 1) {539 if (y >= (window_height - bottom_bar_size) && y < window_height) {
533 current += 1;540 bottom_bar.hovered = true;
534 } else {541 } else {
535 current = 0;542 bottom_bar.hovered = false;
536 }543 }
537 }544
538 tagview.languages.active_id = current.to_string ();545 return false;
539 }
540
541 public void next_text () {
542 int n_text;
543 video_player.playbin.get ("n-text", out n_text);
544 int current = int.parse (tagview.subtitles.active_id);
545
546 if (n_text > 1) {
547 if (current < n_text - 1) {
548 current += 1;
549 } else {
550 current = -1;
551 }
552 }
553 tagview.subtitles.active_id = current.to_string ();
554 }546 }
555547
556 private inline void save_last_played_videos () {548 private inline void save_last_played_videos () {
557 string res = "";549 playlist.save_playlist_config ();
558 for (var i = 0; i < last_played_videos.length () - 1; i ++)
559 res += last_played_videos.nth_data (i) + ",";
560550
561 res += last_played_videos.nth_data (last_played_videos.length () - 1);551 if (settings.last_played_videos.length > 0)
562 settings.last_played_videos = res;552 settings.last_stopped = video_player.progress;
553 else
554 settings.last_stopped = 0;
563 }555 }
564556
565 private void run_open_file () {557 public void run_open_file () {
566 var file = new Gtk.FileChooserDialog (_("Open"), mainwindow, Gtk.FileChooserAction.OPEN,558 var file = new Gtk.FileChooserDialog (_("Open"), mainwindow, Gtk.FileChooserAction.OPEN,
567 Gtk.Stock.CANCEL, Gtk.ResponseType.CANCEL, Gtk.Stock.OPEN, Gtk.ResponseType.ACCEPT);559 _("_Cancel"), Gtk.ResponseType.CANCEL, _("_Open"), Gtk.ResponseType.ACCEPT);
568 file.select_multiple = true;560 file.select_multiple = true;
569561
570 var all_files_filter = new Gtk.FileFilter ();562 var all_files_filter = new Gtk.FileFilter ();
@@ -582,92 +574,95 @@
582 if (file.run () == Gtk.ResponseType.ACCEPT) {574 if (file.run () == Gtk.ResponseType.ACCEPT) {
583 welcome.hide ();575 welcome.hide ();
584 clutter.show_all ();576 clutter.show_all ();
585 for (var i=1;i<file.get_files ().length ();i++) {
586 playlist.add_item (file.get_files ().nth_data (i));
587 }
588 open_file (file.get_uri ());577 open_file (file.get_uri ());
589 settings.last_folder = file.get_current_folder ();578 settings.last_folder = file.get_current_folder ();
590 }579 }
580
591 file.destroy ();581 file.destroy ();
592 }582 }
593583
594 private void run_open_dvd () {584 public void run_open_dvd () {
595 open_file ("dvd://", true);585 read_first_disk.begin ();
586 }
587
588 private async void read_first_disk () {
589 var disk_manager = DiskManager.get_default ();
590 if (disk_manager.get_volumes ().length () <= 0)
591 return;
592 var volume = disk_manager.get_volumes ().nth_data (0);
593 if (volume.can_mount () == true && volume.get_mount ().can_unmount () == false) {
594 try {
595 yield volume.mount (MountMountFlags.NONE, null);
596 } catch (Error e) {
597 critical (e.message);
598 }
599 }
600
601 var root = volume.get_mount ().get_default_location ();
602 open_file (root.get_uri (), true);
596 video_player.playing = true;603 video_player.playing = true;
597604
598 welcome.hide ();605 welcome.hide ();
599 clutter.show_all ();606 clutter.show_all ();
600 }607 }
601608
602 private void toggle_fullscreen ()609 private void toggle_fullscreen () {
603 {610 if (fullscreened) {
604 if (video_player.fullscreened) {
605 mainwindow.unmaximize ();611 mainwindow.unmaximize ();
606 mainwindow.unfullscreen ();612 mainwindow.unfullscreen ();
607 video_player.fullscreened = false;613 fullscreened = false;
608 } else {614 } else {
609 mainwindow.fullscreen ();615 mainwindow.fullscreen ();
610 video_player.fullscreened = true;616 fullscreened = true;
611 }617 }
612 }618 }
613619
614 internal void open_file (string filename, bool dont_modify=false)620 internal void open_file (string filename, bool dont_modify = false) {
615 {
616 var file = File.new_for_commandline_arg (filename);621 var file = File.new_for_commandline_arg (filename);
617622
618 if (file.query_file_type (0) == FileType.DIRECTORY) {623 if (file.query_file_type (0) == FileType.DIRECTORY) {
619 Audience.recurse_over_dir (file, (file_ret) => {624 Audience.recurse_over_dir (file, (file_ret) => {
620 playlist.add_item (file_ret);625 playlist.add_item (file_ret);
621 });626 });
627
622 file = playlist.get_first_item ();628 file = playlist.get_first_item ();
623 } else if (is_subtitle (filename) && video_player.playing) {629 } else if (is_subtitle (filename) && video_player.playing) {
624 video_player.set_subtitle_uri (filename);630 video_player.set_subtitle_uri (filename);
625 return;631 } else if (video_player.playing == true) {
632 playlist.add_item (file);
633 } else {
634 playlist.add_item (file);
635 play_file (file.get_uri ());
626 }636 }
627 else637 }
628 playlist.add_item (file);
629638
630 play_file (file.get_uri ());
631 }
632
633 private bool is_subtitle (string uri) {639 private bool is_subtitle (string uri) {
634 if (uri.length < 4 || uri.get_char (uri.length-4) != '.')640 if (uri.length < 4 || uri.get_char (uri.length-4) != '.')
635 return false;641 return false;
642
636 foreach (string ext in SUBTITLE_EXTENSIONS) {643 foreach (string ext in SUBTITLE_EXTENSIONS) {
637 if (uri.down ().has_suffix (ext))644 if (uri.down ().has_suffix (ext))
638 return true;645 return true;
639 }646 }
647
640 return false;648 return false;
641 }649 }
642650
643 public void play_file (string uri) {651 public void play_file (string uri) {
644 debug ("Opening %s", uri);652 debug ("Opening %s", uri);
645 video_player.uri = uri;653 video_player.uri = uri;
654 bottom_bar.set_preview_uri (uri);
646655
647 mainwindow.title = get_title (uri);656 mainwindow.title = get_title (uri);
648 if (!settings.playback_wait)657 if (!settings.playback_wait)
649 video_player.playing = true;658 video_player.playing = true;
650659
651 if (settings.resume_videos) {
652 int i;
653 for (i = 0; i < last_played_videos.length () && i != -1; i += 2) {
654 if (video_player.uri == last_played_videos.nth_data (i))
655 break;
656 if (i == last_played_videos.length () - 1)
657 i = -1;
658 }
659 if (i != -1 && last_played_videos.nth_data (i + 1) != null) {
660 Idle.add (() => { video_player.progress = double.parse (last_played_videos.nth_data (i + 1)); return false;});
661 debug ("Resuming video from " + last_played_videos.nth_data (i + 1));
662 }
663 }
664
665 Gtk.RecentManager recent_manager = Gtk.RecentManager.get_default ();660 Gtk.RecentManager recent_manager = Gtk.RecentManager.get_default ();
666 recent_manager.add_item (uri);661 recent_manager.add_item (uri);
667662
668 /*subtitles/audio tracks*/663 /*subtitles/audio tracks*/
669 tagview.setup_setup ("text");664 bottom_bar.preferences_popover.setup_text ();
670 tagview.setup_setup ("audio");665 bottom_bar.preferences_popover.setup_audio ();
671 }666 }
672667
673 //the application started668 //the application started
@@ -676,16 +671,15 @@
676 }671 }
677672
678 //the application was requested to open some files673 //the application was requested to open some files
679 public override void open (File [] files, string hint) {674 public override void open (File[] files, string hint) {
680 if (mainwindow == null)675 if (mainwindow == null)
681 activate ();676 activate ();
682677
683 for (var i = 1; i < files.length; i ++)
684 playlist.add_item (files[i]);
685
686 open_file (files[0].get_path ());
687 welcome.hide ();678 welcome.hide ();
688 clutter.show_all ();679 clutter.show_all ();
680 foreach (var file in files) {
681 open_file (file.get_path ());
682 }
689 }683 }
690 }684 }
691}685}
692686
=== added file 'src/CMakeLists.txt'
--- src/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/CMakeLists.txt 2014-07-06 11:18:29 +0000
@@ -0,0 +1,57 @@
1# Vala stuff
2find_package (Vala REQUIRED)
3include (ValaVersion)
4ensure_vala_version ("0.22" MINIMUM)
5include (ValaPrecompile)
6
7# Configure file
8set (CONFIG_FILE ${CMAKE_CURRENT_BINARY_DIR}/config.vala)
9configure_file (${CMAKE_CURRENT_SOURCE_DIR}/Config.vala.cmake ${CONFIG_FILE})
10
11# pkgconfig, real C code
12find_package (PkgConfig)
13
14set (PKG_DEPS granite clutter-gtk-1.0 gstreamer-1.0 gstreamer-pbutils-1.0 gstreamer-tag-1.0)
15set (VALA_DEPS
16 granite
17 clutter-gtk-1.0
18 gdk-x11-3.0
19 gstreamer-1.0
20 gstreamer-pbutils-1.0
21 gstreamer-tag-1.0
22)
23
24pkg_check_modules (DEPS REQUIRED ${PKG_DEPS})
25set (CFLAGS ${DEPS_CFLAGS} ${DEPS_CFLAGS_OTHER})
26link_directories (${DEPS_LIBRARY_DIRS})
27add_definitions (${CFLAGS})
28
29set (EXEC_NAME ${CMAKE_PROJECT_NAME})
30
31vala_precompile (VALA_C ${EXEC_NAME}
32 ${CONFIG_FILE}
33 Audience.vala
34 Consts.vala
35 Settings.vala
36 Utils.vala
37 DiskManager.vala
38 Widgets/BottomBar.vala
39 Widgets/SettingsPopover.vala
40 Widgets/PreviewPopover.vala
41 Widgets/TimeWidget.vala
42 Widgets/Playlist.vala
43 Widgets/PlaylistPopover.vala
44 Widgets/VideoPlayer.vala
45 desktop-launcher.vala
46 PACKAGES
47 ${VALA_DEPS}
48 OPTIONS
49 --enable-experimental
50 --target-glib=2.32 # Remember to keep this updated.
51 --thread
52 -g
53)
54
55add_executable (${EXEC_NAME} ${VALA_C})
56target_link_libraries (${EXEC_NAME} ${DEPS_LIBRARIES})
57install (TARGETS ${EXEC_NAME} RUNTIME DESTINATION bin)
0\ No newline at end of file58\ No newline at end of file
159
=== modified file 'src/Consts.vala'
--- src/Consts.vala 2013-03-31 21:46:37 +0000
+++ src/Consts.vala 2014-07-06 11:18:29 +0000
@@ -1,6 +1,7 @@
11
2namespace Audience {2namespace Audience {
3
4 public const int CONTROLS_HEIGHT = 32;3 public const int CONTROLS_HEIGHT = 32;
4 // 204/255 = 80% opacity
5 public const uint GLOBAL_OPACITY = 204;
56
6}7}
7\ No newline at end of file8\ No newline at end of file
89
=== added file 'src/DiskManager.vala'
--- src/DiskManager.vala 1970-01-01 00:00:00 +0000
+++ src/DiskManager.vala 2014-07-06 11:18:29 +0000
@@ -0,0 +1,98 @@
1// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
2/*-
3 * Copyright (c) 2013-2014 Audience Developers (http://launchpad.net/pantheon-chat)
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authored by: Corentin Noël <corentin@elementaryos.org>
19 */
20
21public class Audience.DiskManager : GLib.Object {
22 public signal void volume_found (Volume volume);
23 public signal void volume_removed (Volume volume);
24
25 private static DiskManager disk_manager = null;
26 public static DiskManager get_default () {
27 if (disk_manager == null) {
28 disk_manager = new DiskManager ();
29 }
30
31 return disk_manager;
32 }
33
34 private GLib.VolumeMonitor monitor;
35 private List<Volume> volumes;
36
37 private DiskManager () {
38 monitor = GLib.VolumeMonitor.get ();
39 volumes = monitor.get_volumes ();
40
41 monitor.drive_changed.connect ((drive) => {
42 debug ("Drive changed: %s\n", drive.get_name ());
43 });
44
45 monitor.drive_connected.connect ((drive) => {
46 debug ("Drive connected: %s", drive.get_name ());
47 });
48
49 monitor.drive_disconnected.connect ((drive) => {
50 debug ("Drive disconnected: %s", drive.get_name ());
51 });
52
53 monitor.drive_eject_button.connect ((drive) => {
54 debug ("Drive eject-button: %s", drive.get_name ());
55 });
56
57 monitor.drive_stop_button.connect ((drive) => {
58 debug ("Drive stop-button:%s", drive.get_name ());
59 });
60
61 monitor.volume_added.connect ((volume) => {
62 check_for_volume (volume);
63 debug ("Volume added: %s", volume.get_name ());
64 });
65
66 monitor.volume_changed.connect ((volume) => {
67 check_for_volume (volume);
68 debug ("Volume changed: %s", volume.get_name ());
69 });
70
71 monitor.volume_removed.connect ((volume) => {
72 volumes.remove (volume);
73 volume_removed (volume);
74 debug ("Volume removed: %s", volume.get_name ());
75 });
76 }
77
78 public GLib.List<Volume> get_volumes () {
79 return volumes.copy ();
80 }
81
82 private void check_for_volume (Volume volume) {
83 if (volume.get_drive ().is_media_check_automatic () == true) {
84 if (volume.get_drive ().has_media () == true) {
85 var root = volume.get_activation_root ();
86 if (root != null) {
87 var video = root.get_child ("VIDEO_TS");
88 var bdmv = root.get_child ("BDMV");
89 var audio = root.get_child ("AUDIO_TS");
90 if (audio.query_exists () == true || video.query_exists () == true || bdmv.query_exists () == true) {
91 volumes.append (volume);
92 volume_found (volume);
93 }
94 }
95 }
96 }
97 }
98}
0\ No newline at end of file99\ No newline at end of file
1100
=== modified file 'src/Settings.vala'
--- src/Settings.vala 2013-03-31 21:46:37 +0000
+++ src/Settings.vala 2014-07-06 11:18:29 +0000
@@ -1,19 +1,36 @@
11// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
2namespace Audience {2/*-
33 * Copyright (c) 2013-2014 Audience Developers (http://launchpad.net/pantheon-chat)
4 public class Settings : Granite.Services.Settings {4 *
5 public bool move_window {get; set;}5 * This program is free software: you can redistribute it and/or modify
6 public bool keep_aspect {get; set;}6 * it under the terms of the GNU General Public License as published by
7 public bool resume_videos {get; set;}7 * the Free Software Foundation, either version 3 of the License, or
8 public string last_played_videos {get; set;} /*video1,time,video2,time2,...*/8 * (at your option) any later version.
9 public string last_folder {get; set;}9
10 public bool playback_wait {get; set;}10 * This program is distributed in the hope that it will be useful,
11 public bool stay_on_top {get; set;}11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 public bool show_window_decoration {get; set;}12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1313 * GNU General Public License for more details.
14 public Settings () {14
15 base ("org.pantheon.Audience");15 * You should have received a copy of the GNU General Public License
16 }16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1717 *
18 * Authored by: Tom Beckmann <tomjonabc@gmail.com>
19 */
20
21public class Audience.Settings : Granite.Services.Settings {
22 public bool move_window {get; set;}
23 public bool keep_aspect {get; set;}
24 public bool resume_videos {get; set;}
25 public string[] last_played_videos {get; set;}
26 public double last_stopped {get; set;}
27 public string last_folder {get; set;}
28 public bool playback_wait {get; set;}
29 public bool stay_on_top {get; set;}
30 public bool show_window_decoration {get; set;}
31
32 public Settings () {
33 base ("org.pantheon.Audience");
18 }34 }
19}35
36}
20\ No newline at end of file37\ No newline at end of file
2138
=== modified file 'src/Utils.vala'
--- src/Utils.vala 2014-04-28 12:58:09 +0000
+++ src/Utils.vala 2014-07-06 11:18:29 +0000
@@ -1,3 +1,22 @@
1// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
2/*-
3 * Copyright (c) 2013-2014 Audience Developers (http://launchpad.net/pantheon-chat)
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authored by: Tom Beckmann <tomjonabc@gmail.com>
19 */
120
2[DBus (name = "org.gnome.SettingsDaemon.MediaKeys")]21[DBus (name = "org.gnome.SettingsDaemon.MediaKeys")]
3public interface GnomeMediaKeys : GLib.Object {22public interface GnomeMediaKeys : GLib.Object {
@@ -8,7 +27,7 @@
827
9[DBus (name = "org.gnome.SessionManager")]28[DBus (name = "org.gnome.SessionManager")]
10public interface GnomeSessionManager : GLib.Object {29public interface GnomeSessionManager : GLib.Object {
11 public abstract bool isSessionRunning() throws GLib.IOError;30 public abstract bool isSessionRunning() throws GLib.IOError;
12 public abstract uint32 Inhibit (string app_id, uint32 toplevel_xid, string reason, uint32 flags) throws GLib.IOError;31 public abstract uint32 Inhibit (string app_id, uint32 toplevel_xid, string reason, uint32 flags) throws GLib.IOError;
13 public abstract void Uninhibit (uint32 inhibit_cookie) throws GLib.IOError;32 public abstract void Uninhibit (uint32 inhibit_cookie) throws GLib.IOError;
14}33}
@@ -18,16 +37,16 @@
18 public static void recurse_over_dir (File file_to_process, FuncOverDir func) {37 public static void recurse_over_dir (File file_to_process, FuncOverDir func) {
19 if (file_to_process.query_file_type (0) == FileType.DIRECTORY) {38 if (file_to_process.query_file_type (0) == FileType.DIRECTORY) {
20 try {39 try {
21 var files = file_to_process.enumerate_children (FileAttribute.STANDARD_NAME, 0);40 var files = file_to_process.enumerate_children (FileAttribute.STANDARD_NAME + "," + FileAttribute.ACCESS_CAN_READ, FileQueryInfoFlags.NONE);
22 FileInfo info;41 FileInfo info;
23 while ((info = files.next_file ()) != null) {42 while ((info = files.next_file ()) != null) {
24 var file = GLib.File.new_for_uri (43 var file = GLib.File.new_for_uri (file_to_process.get_uri () + "/" + info.get_name ());
25 file_to_process.get_uri () +"/"+info.get_name ());44 recurse_over_dir (file, func);
26 recurse_over_dir (file,func);
27 }45 }
28 } catch (Error e) { warning (e.message); }46 } catch (Error e) {
29 }47 critical (e.message);
30 else {48 }
49 } else {
31 func (file_to_process);50 func (file_to_process);
32 }51 }
33 }52 }
@@ -40,216 +59,51 @@
40 }59 }
4160
42 public static string get_extension (string filename) {61 public static string get_extension (string filename) {
43 int i=0;62 for (uint i=filename.length; i!=0; i--) {
44 for (i=filename.length;i!=0;i--) {63 if (filename[i] == '.')
45 if (filename [i] == '.')64 return filename.substring (i+1);
46 break;
47 }65 }
48 return filename.substring (i+1);66
67 return filename;
49 }68 }
5069
51 public static string get_basename (string filename) {70 public static string get_basename (string filename) {
52 int start = 0, end = 0;71 uint end = 0;
53 for (start=filename.length; start != 0; start--) {72 for (uint start=filename.length; start != 0; start--) {
54 if (filename[start] == '/') {73 if (filename[start] == '/') {
55 start ++;74 start ++;
56 break;75 return filename.substring (start, end - start);
57 }76 }
77
58 if (filename[start] == '.' && end == 0)78 if (filename[start] == '.' && end == 0)
59 end = start;79 end = start;
60 }80 }
61 return filename.substring (start, end - start);81
82 return filename.substring (0, end);
62 }83 }
6384
64 public static string seconds_to_time (int seconds) {85 public static string seconds_to_time (int seconds) {
65 int hours = seconds / 3600;86 int hours = seconds / 3600;
66 int minutes = (seconds % 3600) / 60;87 string min = normalize_time ((seconds % 3600) / 60);
67 seconds = seconds % 60;88 string sec = normalize_time (seconds % 60);
6889
69 string time = (hours > 0) ? hours.to_string() + ":" : "";90 if (hours > 0) {
70 time += (((hours > 0) && (minutes < 10)) ? "0" : "") + minutes.to_string() + ":";91 return ("%d:%s:%s".printf (hours, min, sec));
71 time += ((seconds < 10) ? "0" : "") + seconds.to_string();92 } else {
72 return time;93 return ("%s:%s".printf (min, sec));
94 }
95 }
96
97 public static string normalize_time (int time) {
98 if (time < 10) {
99 return "0%d".printf (time);
100 } else {
101 return "%d".printf (time);
102 }
73 }103 }
74104
75 public static bool has_dvd () {105 public static bool has_dvd () {
76 var volume_monitor = GLib.VolumeMonitor.get ();106 var disk_manager = DiskManager.get_default ();
77 var volumes = volume_monitor.get_connected_drives ();107 return disk_manager.get_volumes ().length () > 0;
78
79 for (var i=0; i < volumes.length ();i++) {
80 if (volumes.nth_data (i).get_name ().index_of ("DVD") != -1 &&
81 volumes.nth_data (i).has_media ())
82 return true;
83 }
84
85 return false;
86 }
87
88 public static dynamic Gst.Element get_clutter_sink ()
89 {
90 var sink = Gst.ElementFactory.make ("autocluttersink", "videosink");
91 if (sink == null) {
92 warning ("autocluttersink not available");
93 sink = Gst.ElementFactory.make ("cluttersink", "videosink");
94 }
95
96 return sink;
97 }
98
99 /*
100 * get a thumbnail from a file
101 * @param file the file
102 * @param position the position in the video or -1 for 5%
103 * @param pixbuf gtkclutter texture to put the pixbuf in once it's ready
104 * TODO appears not to load thumbs for bigger files
105 **/
106 /* NOT NEEDED CURRENTLY
107 public static void get_thumb (File file, int64 position, GtkClutter.Texture tex) {
108 //pipeline
109 bool got_video = false;
110 var pipe = new Gst.Pipeline ("pipeline");
111 var src = Gst.ElementFactory.make ("filesrc", "file");
112 dynamic Gst.Element dec = Gst.ElementFactory.make ("decodebin2", "dec");
113
114 pipe.add_many (src, dec);
115 src.link (dec);
116 src.set ("location", file.get_path ());
117 dynamic Gst.Element sink = null;
118 dec.pad_added.connect ( (new_pad) => {
119 if (got_video)
120 return;
121
122 var csp = Gst.ElementFactory.make ("ffmpegcolorspace", "f");
123 var scale = Gst.ElementFactory.make ("videoscale", "s");
124 var filter = Gst.ElementFactory.make ("capsfilter", "c");
125 sink = Gst.ElementFactory.make ("gdkpixbufsink", "sink");
126
127 pipe.add_many (csp, scale, filter, sink);
128
129 var sinkpad = csp.get_static_pad ("sink");
130 new_pad.link (sinkpad);
131
132 csp.link (scale);
133 scale.link (filter);
134 filter.link (sink);
135
136 sink.set_state (Gst.State.PAUSED);
137 filter.set_state (Gst.State.PAUSED);
138 scale.set_state (Gst.State.PAUSED);
139 csp.set_state (Gst.State.PAUSED);
140
141 got_video = true;
142 });
143
144 pipe.get_bus ().add_signal_watch ();
145
146 pipe.set_state (Gst.State.PAUSED);
147
148 bool ready = false;
149 pipe.get_bus ().message.connect ( (bus, msg) => {
150 switch (msg.type) {
151 case Gst.MessageType.ASYNC_DONE:
152 if (msg.src != pipe)
153 break;
154 var fmt = Gst.Format.TIME;
155 int64 pos;
156 pipe.query_position (fmt, out pos);
157 if (pos > 1)
158 ready = true;
159 else
160 break;
161 if (position == -1) {
162 int64 dur;
163 pipe.query_duration (fmt, out dur);
164 pipe.seek_simple (Gst.Format.TIME, Gst.SeekFlags.ACCURATE |
165 Gst.SeekFlags.FLUSH, (int64)(dur*0.5));
166 }else {
167 pipe.seek_simple (Gst.Format.TIME, Gst.SeekFlags.ACCURATE |
168 Gst.SeekFlags.FLUSH, position);
169 }
170 break;
171 case Gst.MessageType.ELEMENT:
172 if (!ready)
173 break;
174 if (msg.src != sink)
175 break;
176 if (!msg.get_structure ().has_name ("prerollpixbuf") &&
177 !msg.get_structure ().has_name ("pixbuf"))
178 break;
179 var val = msg.get_structure ().get_value ("pixbuf");
180 var pixbuf = (Gdk.Pixbuf)val.dup_object ();
181 if (pixbuf == null)
182 return;
183 try {
184 tex.set_from_pixbuf (pixbuf);
185 } catch (Error e) {warning (e.message);}
186 pipe.set_state (Gst.State.NULL);
187 break;
188 default:
189 break;
190 }
191 });
192
193 pipe.set_state (Gst.State.PLAYING);
194 }*/
195
196 namespace Drawing {
197
198 /**
199 * Draws a popover shape
200 */
201 public static void cairo_popover (Cairo.Context cr, double x, double y, double width, double height,
202 double radius, double arrow_height, double arrow_width)
203 {
204 double edge_width = (width - radius * 2);
205 double arrow_offset = (edge_width - arrow_width) / 2;
206
207
208 cr.arc (x + width - radius, y + radius, radius, Math.PI * 1.5, Math.PI * 2);
209 cr.arc (x + width - radius, y + height - radius, radius, 0, Math.PI * 0.5);
210
211 cr.arc (x + radius, y + height - radius, radius, Math.PI * 0.5, Math.PI);
212 cr.arc (x + radius, y + radius, radius, Math.PI, Math.PI * 1.5);
213 cr.move_to (x + radius + arrow_offset, y + height);
214
215 cr.rel_line_to (arrow_width / 2, arrow_height);
216 cr.rel_line_to (arrow_width / 2, -arrow_height);
217
218 cr.close_path ();
219 }
220
221 /**
222 * Draws a 'pill' shape (rounded rectangle with boder radius such that both ends are semicircles)
223 */
224 public static void cairo_pill (Cairo.Context cr, double x, double y, double width, double height) {
225 Granite.Drawing.Utilities.cairo_rounded_rectangle (cr, x, y, width, height, height / 2);
226 }
227
228 /**
229 * Draws a ' halfpill' shape (rounded rectangle with boder radius such that one ends is a semicircle)
230 */
231 public static void cairo_half_pill (Cairo.Context cr, double x, double y, double width, double height, Gtk.PositionType side) {
232 double radius = height / 2;
233 cr.move_to (x + radius, y);
234 switch (side) {
235 case Gtk.PositionType.LEFT:
236 cr.arc (x + width - radius, y + radius, radius, Math.PI * 1.5, Math.PI * 0.5);
237 cr.line_to ((int)x, y + height); // (int) required to not draw 'half' pixels (blurry)
238 cr.line_to ((int)x, y);
239 cr.line_to ((int)(x + width - radius), y);
240 break;
241 case Gtk.PositionType.RIGHT:
242 cr.arc (x + radius, y + height - radius, radius, Math.PI * 0.5, Math.PI * 1.5);
243 cr.line_to ((int)(x + width), y);
244 cr.line_to ((int)(x + width), y + height);
245 cr.line_to ((int)(x + radius), y + height);
246 break;
247 default:
248 assert_not_reached();
249 }
250 cr.close_path ();
251 }
252
253
254 }108 }
255}109}
256\ No newline at end of file110\ No newline at end of file
257111
=== added file 'src/Widgets/BottomBar.vala'
--- src/Widgets/BottomBar.vala 1970-01-01 00:00:00 +0000
+++ src/Widgets/BottomBar.vala 2014-07-06 11:18:29 +0000
@@ -0,0 +1,160 @@
1// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
2/*-
3 * Copyright (c) 2013-2014 Audience Developers (http://launchpad.net/pantheon-chat)
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authored by: Corentin Noël <corentin@elementaryos.org>
19 */
20
21public class Audience.Widgets.BottomBar : Gtk.Revealer {
22 public signal void play_toggled ();
23 public signal void unfullscreen ();
24 public signal void seeked (double val);
25
26 public bool hovered { get; set; default=false; }
27 public bool fullscreen { get; set; default=false; }
28 public SettingsPopover preferences_popover;
29 public TimeWidget time_widget;
30
31 private Gtk.Button play_button;
32 private Gtk.Button preferences_button;
33 private Gtk.Revealer unfullscreen_revealer;
34 private PlaylistPopover playlist_popover;
35 private bool is_playing = false;
36 private uint hiding_timer = 0;
37
38 public BottomBar () {
39 transition_type = Gtk.RevealerTransitionType.CROSSFADE;
40 var main_actionbar = new Gtk.ActionBar ();
41 main_actionbar.opacity = GLOBAL_OPACITY;
42
43 play_button = new Gtk.Button.from_icon_name ("media-playback-start-symbolic", Gtk.IconSize.BUTTON);
44 play_button.tooltip_text = _("Play");
45 play_button.clicked.connect (() => {play_toggled ();});
46
47 var playlist_button = new Gtk.Button.from_icon_name ("view-list-symbolic", Gtk.IconSize.BUTTON);
48 playlist_button.tooltip_text = _("Playlist");
49 playlist_button.clicked.connect (() => {playlist_popover.show_all (); playlist_popover.queue_resize ();});
50
51 preferences_button = new Gtk.Button.from_icon_name ("document-properties-symbolic", Gtk.IconSize.BUTTON);
52 preferences_button.tooltip_text = _("Settings");
53 preferences_button.clicked.connect (() => {preferences_popover.show_all (); preferences_popover.queue_resize ();});
54
55 time_widget = new TimeWidget ();
56 time_widget.seeked.connect ((val) => {seeked (val);});
57
58 playlist_popover = new PlaylistPopover ();
59 playlist_popover.relative_to = playlist_button;
60 preferences_popover = new SettingsPopover ();
61 preferences_popover.relative_to = preferences_button;
62
63 main_actionbar.pack_start (play_button);
64 main_actionbar.set_center_widget (time_widget);
65 main_actionbar.pack_end (preferences_button);
66 main_actionbar.pack_end (playlist_button);
67 add (main_actionbar);
68
69 notify["hovered"].connect (() => {
70 if (hovered == false) {
71 set_timeout ();
72 } else {
73 if (hiding_timer != 0) {
74 Source.remove (hiding_timer);
75 hiding_timer = 0;
76 }
77 }
78 });
79
80 notify["fullscreen"].connect (() => {
81 if (fullscreen == true && child_revealed == true) {
82 unfullscreen_revealer.set_reveal_child (true);
83 } else if (fullscreen == false && child_revealed == true) {
84 unfullscreen_revealer.set_reveal_child (false);
85 }
86 });
87
88 show_all ();
89 }
90
91 public void set_preview_uri (string uri) {
92 time_widget.set_preview_uri (uri);
93 }
94
95 public Gtk.Revealer get_unfullscreen_button () {
96 unfullscreen_revealer = new Gtk.Revealer ();
97 unfullscreen_revealer.opacity = GLOBAL_OPACITY;
98 unfullscreen_revealer.get_style_context ().add_class ("header-bar");
99 unfullscreen_revealer.transition_type = Gtk.RevealerTransitionType.CROSSFADE;
100 var unfullscreen_button = new Gtk.Button.from_icon_name ("view-restore-symbolic", Gtk.IconSize.BUTTON);
101 unfullscreen_button.tooltip_text = _("Unfullscreen");
102 unfullscreen_button.clicked.connect (() => {unfullscreen ();});
103 unfullscreen_revealer.add (unfullscreen_button);
104 unfullscreen_revealer.show_all ();
105 return unfullscreen_revealer;
106 }
107
108 public void toggle_play_pause () {
109 is_playing = !is_playing;
110 if (is_playing == true) {
111 play_button.image = new Gtk.Image.from_icon_name ("media-playback-pause-symbolic", Gtk.IconSize.BUTTON);
112 play_button.tooltip_text = _("Pause");
113 set_timeout ();
114 } else {
115 play_button.image = new Gtk.Image.from_icon_name ("media-playback-start-symbolic", Gtk.IconSize.BUTTON);
116 play_button.tooltip_text = _("Play");
117 set_reveal_child (true);
118 }
119 }
120
121 public new void set_reveal_child (bool reveal) {
122 base.set_reveal_child (reveal);
123 if (reveal == true && fullscreen == true) {
124 unfullscreen_revealer.set_reveal_child (reveal);
125 } else if (reveal == false) {
126 unfullscreen_revealer.set_reveal_child (reveal);
127 }
128 }
129
130 public override void get_preferred_width (out int minimum_width, out int natural_width) {
131 base.get_preferred_width (out minimum_width, out natural_width);
132 if (parent.get_window () == null)
133 return;
134
135 var width = parent.get_window ().get_width ();
136 if (width > 0 && width >= minimum_width) {
137 natural_width = width;
138 }
139 }
140
141 public void set_progression_time (double current_time, double total_time) {
142 time_widget.set_progression_time (current_time, total_time);
143 }
144
145 private void set_timeout () {
146 if (hiding_timer != 0)
147 Source.remove (hiding_timer);
148
149 hiding_timer = GLib.Timeout.add (2000, () => {
150 if (hovered == true || preferences_popover.visible == true || playlist_popover.visible == true || is_playing == false) {
151 hiding_timer = 0;
152 return false;
153 }
154 set_reveal_child (false);
155 unfullscreen_revealer.set_reveal_child (false);
156 hiding_timer = 0;
157 return false;
158 });
159 }
160}
0\ No newline at end of file161\ No newline at end of file
1162
=== removed file 'src/Widgets/Button.vala'
--- src/Widgets/Button.vala 2013-05-19 17:10:26 +0000
+++ src/Widgets/Button.vala 1970-01-01 00:00:00 +0000
@@ -1,53 +0,0 @@
1
2namespace Audience.Widgets{
3
4 public class Button : GtkClutter.Texture {
5 public signal void clicked ();
6
7 bool pressed = false;
8
9 public Button (string icon, string fallback, string alt_fallback=""){
10 set_icon (icon, fallback, alt_fallback);
11
12 reactive = true;
13 width = 16;
14 height = 16;
15 opacity = 255;
16 }
17
18 public override bool leave_event (Clutter.CrossingEvent event) {
19 animate (Clutter.AnimationMode.EASE_OUT_QUAD, 200, opacity:255);
20 return true;
21 }
22
23 public override bool enter_event (Clutter.CrossingEvent event) {
24 animate (Clutter.AnimationMode.EASE_OUT_QUAD, 200, opacity:170);
25 return true;
26 }
27
28 public override bool button_press_event (Clutter.ButtonEvent event) {
29 pressed = true;
30 return true;
31 }
32
33 public override bool button_release_event (Clutter.ButtonEvent event) {
34 if (pressed) {
35 clicked ();
36 pressed = false;
37 }
38 return true;
39 }
40
41 public void set_icon (string icon, string fallback, string alt_fallback="") {
42 try {
43 var ti = new ThemedIcon.from_names ({icon, alt_fallback, fallback});
44 var l = Gtk.IconTheme.get_default ().lookup_by_gicon (ti, 16, 0);
45 if (l != null) {
46 this.set_from_pixbuf (l.load_symbolic ({1.0,1.0,1.0,1.0}, null, null, null, null));
47 } else {
48 warning("NULL detected when trying to load icon: " + icon + " (or " + fallback + ")");
49 }
50 } catch (Error e){warning (e.message);}
51 }
52 }
53}
540
=== removed file 'src/Widgets/ControlsBar.vala'
--- src/Widgets/ControlsBar.vala 2013-05-19 17:10:26 +0000
+++ src/Widgets/ControlsBar.vala 1970-01-01 00:00:00 +0000
@@ -1,137 +0,0 @@
1using Clutter;
2
3namespace Audience.Widgets
4{
5 public class Controls : Actor
6 {
7 public MediaSlider slider;
8 public Button play;
9 public Button view;
10 public Button open;
11
12 public Text current;
13 public Text remaining;
14
15 private Gdk.Pixbuf play_pix;
16 private Gdk.Pixbuf pause_pix;
17
18 public bool showing_view = false;
19 public bool hovered { get; set; }
20
21 public Controls ()
22 {
23 layout_manager = new BoxLayout ();
24 content = new Canvas ();
25
26 (layout_manager as BoxLayout).spacing = 10;
27
28 this.current = new Text.full ("", "0", {255,255,255,255});
29 this.remaining = new Text.full ("", "0", {255,255,255,255});
30
31 this.slider = new MediaSlider ();
32
33 this.play = new Button ("media-playback-start-symbolic", Gtk.Stock.MEDIA_PLAY);
34
35 this.view = new Button ("pane-show-symbolic", Gtk.Stock.GO_BACK, "go-previous-symbolic");
36
37 this.open = new Button ("list-add-symbolic", Gtk.Stock.OPEN);
38
39 var spacer_left = new Rectangle.with_color ({0,0,0,0});
40 spacer_left.width = 0;
41 var spacer_right = new Rectangle.with_color ({0,0,0,0});
42 spacer_right.width = 0;
43
44 this.add_child (spacer_left);
45 this.add_child (this.play);
46 this.add_child (this.current);
47 this.add_child (this.slider);
48 this.add_child (this.remaining);
49 this.add_child (this.open);
50 this.add_child (this.view);
51 this.add_child (spacer_right);
52
53 (layout_manager as BoxLayout).set_expand (slider, true);
54 (layout_manager as BoxLayout).set_fill (slider, true, true);
55
56 /*setup a css style for the control background*/
57 var style_holder = new Gtk.EventBox ();
58 var css = new Gtk.CssProvider ();
59 try{css.load_from_data ("""
60 * {
61 engine: unico;
62 background-image: -gtk-gradient (linear,
63 left top, left bottom,
64 from (alpha(#323232, 0.698)),
65 to (alpha(#242424, 0.698)));
66
67 -unico-outer-stroke-gradient: -gtk-gradient (linear,
68 left top, left bottom,
69 from (alpha(#161616, 0.698)),
70 to (alpha(#000000, 0.698)));
71 -unico-inner-stroke-gradient: -gtk-gradient (linear,
72 left top, left bottom,
73 from (alpha(#ffffff, 0.149)),
74 color-stop (0.1, alpha(#ffffff, 0.035)),
75 color-stop (0.9, alpha(#ffffff, 0.024)),
76 to (alpha(#ffffff, 0.059)));
77 -unico-inner-stroke-width: 1;
78 -unico-outer-stroke-width: 1;
79 }
80 """, -1);}catch (Error e){warning (e.message);}
81 style_holder.get_style_context ().add_provider (css, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
82
83 (content as Canvas).draw.connect ( (ctx) => {
84 ctx.set_operator (Cairo.Operator.CLEAR);
85 ctx.paint ();
86 ctx.set_operator (Cairo.Operator.OVER);
87
88 style_holder.get_style_context ().render_background (ctx, -2, 0, width+4, CONTROLS_HEIGHT+1);
89 style_holder.get_style_context ().render_frame (ctx, -2, 0, width+4, CONTROLS_HEIGHT+1);
90
91 return false;
92 });
93 (content as Canvas).set_size (500, CONTROLS_HEIGHT);
94
95 try {
96 var l = Gtk.IconTheme.get_default ().lookup_icon ("media-playback-pause-symbolic", 16, 0);
97 if (l == null)
98 this.pause_pix = new Gtk.Image.from_stock (Gtk.Stock.MEDIA_PAUSE, Gtk.IconSize.LARGE_TOOLBAR).pixbuf;
99 else
100 this.pause_pix = l.load_symbolic ({1.0,1.0,1.0,1.0}, null, null, null, null);
101 } catch (Error e) { warning (e.message); }
102
103 try {
104 var l = Gtk.IconTheme.get_default ().lookup_icon ("media-playback-start-symbolic", 16, 0);
105 if (l == null)
106 this.play_pix = new Gtk.Image.from_stock (Gtk.Stock.MEDIA_PLAY, Gtk.IconSize.LARGE_TOOLBAR).pixbuf;
107 else
108 this.play_pix = l.load_symbolic ({1.0,1.0,1.0,1.0}, null, null, null, null);
109 } catch (Error e) { warning (e.message); }
110
111 this.height = CONTROLS_HEIGHT;
112
113 this.reactive = true;
114 this.enter_event.connect ( () => {
115 this.hovered = true;
116 return false;
117 });
118 this.leave_event.connect ( (e) => {
119 if (!contains (e.related))
120 this.hovered = false;
121 return false;
122 });
123 }
124
125 // catch all button presses
126 public override bool button_press_event (Clutter.ButtonEvent event) {
127 return true;
128 }
129
130 public void show_play_button (bool show){ /*or show pause button*/
131 try{
132 this.play.set_from_pixbuf ((show)?play_pix:pause_pix);
133 }catch (Error e){warning (e.message);}
134 }
135 }
136
137}
1380
=== removed file 'src/Widgets/LLabel.vala'
--- src/Widgets/LLabel.vala 2012-08-21 14:56:49 +0000
+++ src/Widgets/LLabel.vala 1970-01-01 00:00:00 +0000
@@ -1,27 +0,0 @@
1
2namespace Audience.Widgets{
3
4 class LLabel : Gtk.Label {
5 public LLabel (string label) {
6 this.set_halign (Gtk.Align.START);
7 this.label = label;
8 }
9 public LLabel.indent (string label) {
10 this (label);
11 this.margin_left = 10;
12 }
13 public LLabel.markup (string label) {
14 this (label);
15 this.use_markup = true;
16 }
17 public LLabel.right (string label) {
18 this.set_halign (Gtk.Align.END);
19 this.label = label;
20 }
21 public LLabel.right_with_markup (string label) {
22 this.set_halign (Gtk.Align.END);
23 this.use_markup = true;
24 this.label = label;
25 }
26 }
27}
280
=== removed file 'src/Widgets/MediaSlider.vala'
--- src/Widgets/MediaSlider.vala 2014-04-28 12:58:09 +0000
+++ src/Widgets/MediaSlider.vala 1970-01-01 00:00:00 +0000
@@ -1,238 +0,0 @@
1
2namespace Audience.Widgets{
3
4 public class MediaSlider : Clutter.Group {
5
6 public signal void seeked (double new_progress);
7
8 public Clutter.Texture preview;
9 public Clutter.Actor preview_bg;
10 dynamic Gst.Element preview_playbin;
11 dynamic Gst.Element sink;
12
13 double progress_stacked = 0.0;
14 bool seeking = false;
15
16 private double _buffered;
17 public double buffered{
18 get { return _buffered; }
19 set { _buffered = value; this.bar.invalidate (); }
20 }
21
22 private double _progress;
23 public double progress{
24 get { return _progress; }
25 set { _progress = value; this.bar.invalidate (); }
26 }
27
28 private Clutter.CairoTexture bar;
29
30 private const int BAR_HEIGHT = 8;
31
32 /*the mouse is currently on the controls*/
33 public bool mouse_grabbed = false;
34
35 public MediaSlider () {
36 this.preview = new Clutter.Texture ();
37 this._buffered = 0.0;
38 this._progress = 0.0;
39 this.bar = new Clutter.CairoTexture (1, BAR_HEIGHT);
40
41 preview.filter_quality = Clutter.TextureQuality.HIGH;
42 preview.scale_x = 0.0;
43 preview.scale_y = 0.0;
44 preview.scale_gravity = Clutter.Gravity.CENTER;
45 preview.height = 90.0f;
46 // preview.width is set in VideoPlayer.vala
47
48 // connect gstreamer stuff
49 preview_playbin = Gst.ElementFactory.make ("playbin", "play");
50 preview_playbin.get_bus ().add_signal_watch ();
51 preview_playbin.get_bus ().message.connect ((msg) => {
52 switch (msg.type) {
53 case Gst.MessageType.STATE_CHANGED:
54 if (progress_stacked != 0)
55 seek (progress_stacked);
56 break;
57 case Gst.MessageType.ASYNC_DONE:
58 if (seeking) {
59 seeking = false;
60 if (progress_stacked != 0)
61 seek (progress_stacked);
62 }
63 break;
64 }
65 });
66 sink = Audience.get_clutter_sink ();
67 sink.texture = preview;
68 preview_playbin.video_sink = sink;
69
70 preview_bg = new Clutter.Actor ();
71 preview_bg.y = -120.0f;
72 preview_bg.add_constraint (new Clutter.BindConstraint (preview, Clutter.BindCoordinate.WIDTH, 30.0f));
73 preview_bg.add_constraint (new Clutter.BindConstraint (preview, Clutter.BindCoordinate.HEIGHT, 45.0f));
74 preview_bg.opacity = 0;
75 preview_bg.content = new Clutter.Canvas ();
76 preview_bg.allocation_changed.connect (() => {
77 (preview_bg.content as Clutter.Canvas).set_size ((int)preview_bg.width, (int)preview_bg.height);
78 });
79 var ARROW_HEIGHT = 17;
80 var ARROW_WIDTH = 20;
81 var popover_grad = new Cairo.Pattern.linear (0, 0, 0, preview_bg.height);
82 popover_grad.add_color_stop_rgba (0.0, 0.243, 0.243, 0.243, 0.7);
83 popover_grad.add_color_stop_rgba (1.0, 0.094, 0.094, 0.094, 0.7);
84
85 var popover_inset_grad = new Cairo.Pattern.linear (0, 0, 0, preview_bg.height);
86 popover_inset_grad.add_color_stop_rgba (0.0, 1, 1, 1, 0.3);
87 popover_inset_grad.add_color_stop_rgba (1.0, 1, 1, 1, 0.1);
88 (preview_bg.content as Clutter.Canvas).draw.connect ( (ctx) => {
89 ctx.set_operator (Cairo.Operator.CLEAR);
90 ctx.paint ();
91 ctx.set_operator (Cairo.Operator.OVER);
92
93 // Outline
94 Drawing.cairo_popover (ctx, 0, 0, preview_bg.width,
95 preview_bg.height - ARROW_HEIGHT, 3, ARROW_WIDTH, ARROW_HEIGHT);
96 ctx.set_source_rgba (0, 0, 0, 0.7);
97 ctx.fill ();
98
99 // Inset border
100 Drawing.cairo_popover (ctx, 1, 1, preview_bg.width - 2,
101 preview_bg.height - 2 - ARROW_HEIGHT, 3, ARROW_WIDTH - 2, ARROW_HEIGHT - 2);
102 ctx.set_source (popover_inset_grad);
103 ctx.fill ();
104
105 ctx.set_operator(Cairo.Operator.SOURCE);
106 // Fill
107 Drawing.cairo_popover (ctx, 2, 2, preview_bg.width - 4,
108 preview_bg.height - 4 - ARROW_HEIGHT, 3, ARROW_WIDTH - 4, ARROW_HEIGHT - 4);
109 ctx.set_source (popover_grad);
110 ctx.fill ();
111
112 ctx.set_operator(Cairo.Operator.OVER);
113 return true;
114 });
115
116 this.bar.y = CONTROLS_HEIGHT / 2 - BAR_HEIGHT / 2;
117 this.bar.auto_resize = true;
118 var bar_grad = new Cairo.Pattern.linear (0, 0, 0, BAR_HEIGHT);
119 bar_grad.add_color_stop_rgba (0.0, 0.254, 0.247, 0.231, 0.4);
120 bar_grad.add_color_stop_rgba (1.0, 0.298, 0.290, 0.282, 0.4);
121 var bar_shadow_grad = new Cairo.Pattern.linear (0, 0, 0, BAR_HEIGHT);
122 bar_shadow_grad.add_color_stop_rgba (0.0, 1, 1, 1, 0);
123 bar_shadow_grad.add_color_stop_rgba (1.0, 1, 1, 1, 0.2);
124 this.bar.draw.connect ( (ctx) => {
125 this.bar.clear();
126 //drop shadow
127 Drawing.cairo_pill (ctx, 0, 0, this.bar.width, BAR_HEIGHT);
128 ctx.set_source (bar_shadow_grad);
129 ctx.fill ();
130 //outline
131 Drawing.cairo_pill (ctx, 1, 1, this.bar.width - 2, BAR_HEIGHT - 2);
132 ctx.set_source_rgba (0, 0, 0, 0.4);
133 ctx.fill ();
134 //bg
135 Drawing.cairo_pill (ctx, 2, 2, this.bar.width - 4, BAR_HEIGHT - 4);
136 ctx.set_source (bar_grad);
137 ctx.fill ();
138 //buffering
139 if (this._buffered != 0.0){
140 int64 duration;
141 preview_playbin.query_duration (Gst.Format.TIME, out duration);
142 Drawing.cairo_half_pill (ctx, 2, 2,
143 (this._buffered / duration * this.bar.width) - 4, BAR_HEIGHT - 4, Gtk.PositionType.RIGHT);
144 ctx.set_source_rgb (0.6, 0.6, 0.6);
145 ctx.fill ();
146 }
147 //progress
148 if (this._progress != 0.0){
149 Drawing.cairo_half_pill (ctx, 2, 2, (this._progress * this.width) - 4, BAR_HEIGHT - 4, Gtk.PositionType.RIGHT);
150 ctx.set_source_rgb (1.0, 1.0, 1.0);
151 ctx.fill ();
152 }
153 return true;
154 });
155
156 var scalex = new Clutter.BindConstraint (this, Clutter.BindCoordinate.WIDTH, 0);
157 bar.add_constraint (scalex);
158
159 //seek
160 preview.reactive = true;
161
162 reactive = true;
163 add_child (bar);
164 add_child (preview_bg);
165 }
166
167 public override bool motion_event (Clutter.MotionEvent event)
168 {
169 float local_x, local_y;
170 this.transform_stage_point (event.x, event.y, out local_x, out local_y);
171
172 preview.x = event.x - preview.width / 2;
173 preview_bg.x = local_x - preview.width / 2 - 15.0f;
174
175 seek (float.max (local_x, 0.0000001f) / this.width);
176
177 return true;
178 }
179
180 public override bool enter_event (Clutter.CrossingEvent event)
181 {
182 this.preview.animate (Clutter.AnimationMode.EASE_OUT_ELASTIC, 800,
183 scale_x:1.0, scale_y:1.0);
184 preview_bg.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 500, opacity:240);
185 preview_toggle_playing (true);
186 this.mouse_grabbed = true;
187 return false;
188 }
189
190 public override bool leave_event (Clutter.CrossingEvent event)
191 {
192 preview.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 150,
193 scale_x:0.0, scale_y:0.0);
194 preview_bg.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 150, opacity:0);
195 preview_toggle_playing (false);
196 mouse_grabbed = false;
197 return false;
198 }
199
200 public override bool button_release_event (Clutter.ButtonEvent event)
201 {
202 float x, y;
203 this.transform_stage_point (event.x, event.y, out x, out y);
204 this.seeked (x / this.width);
205 return true;
206 }
207
208 public void set_preview_uri (string uri)
209 {
210 preview_playbin.set_state (Gst.State.READY);
211 preview_playbin.uri = uri;
212 preview_playbin.volume = 0.0;
213 }
214
215 void preview_toggle_playing (bool play)
216 {
217 this.preview_playbin.set_state (play ? Gst.State.PLAYING : Gst.State.PAUSED);
218 }
219
220 void seek (double progress)
221 {
222 if (seeking) {
223 progress_stacked = progress;
224 return;
225 }
226
227 int64 duration;
228 preview_playbin.query_duration (Gst.Format.TIME, out duration);
229 preview_playbin.seek (1.0, Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT,
230 Gst.SeekType.SET, (int64)(progress * duration),
231 Gst.SeekType.NONE, (int64)Gst.CLOCK_TIME_NONE);
232
233 this.progress_stacked = 0;
234
235 seeking = true;
236 }
237 }
238}
2390
=== modified file 'src/Widgets/Playlist.vala'
--- src/Widgets/Playlist.vala 2012-08-21 14:56:49 +0000
+++ src/Widgets/Playlist.vala 2014-07-06 11:18:29 +0000
@@ -1,93 +1,98 @@
11// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
2/*-
3 * Copyright (c) 2013-2014 Audience Developers (http://launchpad.net/pantheon-chat)
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authored by: Tom Beckmann <tomjonabc@gmail.com>
19 */
220
3namespace Audience.Widgets {21namespace Audience.Widgets {
4
5 public class Playlist : Gtk.TreeView {22 public class Playlist : Gtk.TreeView {
623 // the player is requested to play path
7 /*the player is requested to play path*/
8 public signal void play (File path);24 public signal void play (File path);
925
10 private int current;26 private enum Columns {
11 private Gtk.ListStore playlist;27 PLAYING,
28 TITLE,
29 FILENAME,
30 N_COLUMNS
31 }
32
33 private int current = 0;
34 private Gtk.ListStore playlist;
1235
13 public Playlist () {36 public Playlist () {
14 this.current = 0;37 this.playlist = new Gtk.ListStore (Columns.N_COLUMNS, typeof (Icon), typeof (string), typeof (string));
15 this.playlist = new Gtk.ListStore (4, typeof (Gdk.Pixbuf), /*playing*/
16 typeof (Gdk.Pixbuf), /*icon*/
17 typeof (string), /*title*/
18 typeof (string)); /*filename*/
19 this.model = this.playlist;38 this.model = this.playlist;
20 this.expand = true;39 this.expand = true;
21 this.headers_visible = false;40 this.headers_visible = false;
41 this.activate_on_single_click = true;
42 this.can_focus = false;
43 get_selection ().mode = Gtk.SelectionMode.NONE;
2244
23 var text_render = new Gtk.CellRendererText ();45 var text_render = new Gtk.CellRendererText ();
24 text_render.ellipsize = Pango.EllipsizeMode.END;46 text_render.ellipsize = Pango.EllipsizeMode.END;
2547
26 this.insert_column_with_attributes (-1, "", new Gtk.CellRendererPixbuf (),48 this.insert_column_with_attributes (-1, "Playing", new Gtk.CellRendererPixbuf (), "gicon", Columns.PLAYING);
27 "pixbuf", 0);49 this.insert_column_with_attributes (-1, "Title", text_render, "text", Columns.TITLE);
28 this.insert_column_with_attributes (-1, "", new Gtk.CellRendererPixbuf (),
29 "pixbuf", 1);
30 this.insert_column_with_attributes (-1, "", text_render, "text", 2);
3150
32 this.row_activated.connect ( (path ,col) => {51 this.row_activated.connect ((path ,col) => {
33 Gtk.TreeIter iter;52 Gtk.TreeIter iter;
34 playlist.get_iter (out iter, path);53 playlist.get_iter (out iter, path);
35 string filename;54 string filename;
36 playlist.get (iter, 3, out filename);55 playlist.get (iter, Columns.FILENAME, out filename);
37 play (File.new_for_commandline_arg (filename));56 play (File.new_for_commandline_arg (filename));
38 change_current_symbol (iter);57 change_current_symbol (iter);
39 this.current = int.parse (path.to_string ());58 this.current = int.parse (path.to_string ());
40 });59 });
4160
42 this.reorderable = true;61 this.reorderable = true;
43 this.model.row_inserted.connect ( (path, iter) => {62 this.model.row_inserted.connect ((path, iter) => {
44 Gtk.TreeIter it;63 Gtk.TreeIter it;
45 playlist.get_iter (out it, path);64 playlist.get_iter (out it, path);
46 Gdk.Pixbuf playing;65 Gdk.Pixbuf playing;
47 playlist.get (it, 0, out playing);66 playlist.get (it, Columns.PLAYING, out playing);
48 if (playing != null) //if playing is not null it's the current item67 if (playing != null) //if playing is not null it's the current item
49 this.current = int.parse (path.to_string ());68 this.current = int.parse (path.to_string ());
50 });69 });
51
52 var css_fix = new Gtk.CssProvider ();
53 try {
54 css_fix.load_from_data ("
55 * {
56 background-image:none;
57 background-color:@transparent;
58 border-color:@transparent;
59 }", -1);
60 } catch (Error e) { warning (e.message); }
61 this.get_style_context ().add_provider (css_fix, 20000);
62 }70 }
6371
64 private inline void change_current_symbol (Gtk.TreeIter new_item) {72 private inline void change_current_symbol (Gtk.TreeIter new_item) {
65 try{
66 playlist.set (new_item, 0, Gtk.IconTheme.get_default ().
67 load_icon ("media-playback-start-symbolic", 16, 0));
68 }catch (Error e) { warning (e.message); }
69 Gtk.TreeIter old_item;73 Gtk.TreeIter old_item;
70 playlist.get_iter_from_string (out old_item, this.current.to_string ());74 playlist.get_iter_from_string (out old_item, this.current.to_string ());
71 playlist.set (old_item, 0, null);75 playlist.set (old_item, Columns.PLAYING, null);
76 playlist.set (new_item, Columns.PLAYING, new ThemedIcon ("media-playback-start-symbolic"));
72 }77 }
7378
74 public void next () {79 public void next () {
75 Gtk.TreeIter it;80 Gtk.TreeIter iter;
76 if (playlist.get_iter_from_string (out it, (this.current + 1).to_string ())){81 if (playlist.get_iter_from_string (out iter, (this.current + 1).to_string ())){
77 string filename;82 string filename;
78 playlist.get (it, 3, out filename);83 playlist.get (iter, Columns.FILENAME, out filename);
79 change_current_symbol (it);84 change_current_symbol (iter);
80 current++;85 current++;
81 play (File.new_for_commandline_arg (filename));86 play (File.new_for_commandline_arg (filename));
82 }87 }
83 }88 }
8489
85 public void previous () {90 public void previous () {
86 Gtk.TreeIter it;91 Gtk.TreeIter iter;
87 if (playlist.get_iter_from_string (out it, (this.current - 1).to_string ())){92 if (playlist.get_iter_from_string (out iter, (this.current - 1).to_string ())){
88 string filename;93 string filename;
89 playlist.get (it, 3, out filename);94 playlist.get (iter, Columns.FILENAME, out filename);
90 change_current_symbol (it);95 change_current_symbol (iter);
91 current--;96 current--;
92 play (File.new_for_commandline_arg (filename));97 play (File.new_for_commandline_arg (filename));
93 }98 }
@@ -95,37 +100,67 @@
95100
96 public void add_item (File path) {101 public void add_item (File path) {
97 Gtk.TreeIter iter;102 Gtk.TreeIter iter;
98 Gdk.Pixbuf pix = null; //may becoming the thumb...
99103
100 Gdk.Pixbuf? playing = null;104 Icon? playing = null;
101 Gtk.TreeIter dummy;105 Gtk.TreeIter dummy;
102 if (!playlist.get_iter_first (out dummy)){ //first item106 if (!playlist.get_iter_first (out dummy)){
103 try {107 playing = new ThemedIcon ("media-playback-start-symbolic");
104 playing = Gtk.IconTheme.get_default ().lookup_icon ("media-playback-start-symbolic",
105 16, 0).load_symbolic ({0, 0, 0, 255}, null, null, null);
106 } catch (Error e) { warning (e.message); }
107 } else {108 } else {
108 playing = null;109 playing = null;
109 }110 }
110111
111 playlist.append (out iter);112 playlist.append (out iter);
112 playlist.set (iter, 0, playing, 1, pix,113 playlist.set (iter, Columns.PLAYING, playing,
113 2, Audience.get_title (path.get_basename ()), 3, path.get_path ());114 Columns.TITLE, Audience.get_title (path.get_basename ()),
115 Columns.FILENAME, path.get_path ());
114 }116 }
115117
116 public void remove_item (File path) {118 public void remove_item (File path) {
117 /*not needed up to now*/119 /*not needed up to now*/
118 }120 }
121
119 public File? get_first_item () {122 public File? get_first_item () {
120 Gtk.TreeIter it;123 Gtk.TreeIter iter;
121 if (playlist.get_iter_from_string (out it, 0.to_string ())){124 if (playlist.get_iter_first (out iter)){
122 string filename;125 string filename;
123 playlist.get (it, 3, out filename);126 playlist.get (iter, Columns.FILENAME, out filename);
124 return File.new_for_commandline_arg (filename);127 return File.new_for_commandline_arg (filename);
125 }128 }
126 return null;129 return null;
127 }130 }
128131
132 public List<string> get_all_items () {
133 var list = new List<string> ();
134 playlist.foreach ((model, path, iter) => {
135 Value filename;
136 playlist.get_value (iter, Columns.FILENAME, out filename);
137 string name = filename.get_string ();
138 list.append (name);
139 return false;
140 });
141 return list.copy ();
142 }
143
144 public void save_playlist_config () {
145 var list = new List<string> ();
146 playlist.foreach ((model, path, iter) => {
147 Value filename;
148 playlist.get_value (iter, Columns.FILENAME, out filename);
149 string name = filename.get_string ();
150 list.append (name);
151 return false;
152 });
153
154 uint i = 0;
155 var videos = new string[list.length ()];
156 foreach (var filename in list) {
157 videos[i] = filename;
158 i++;
159 }
160
161 settings.last_played_videos = videos;
162 }
163
129 }164 }
130165
131}166}
132\ No newline at end of file167\ No newline at end of file
133168
=== added file 'src/Widgets/PlaylistPopover.vala'
--- src/Widgets/PlaylistPopover.vala 1970-01-01 00:00:00 +0000
+++ src/Widgets/PlaylistPopover.vala 2014-07-06 11:18:29 +0000
@@ -0,0 +1,116 @@
1// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
2/*-
3 * Copyright (c) 2013-2014 Audience Developers (http://launchpad.net/pantheon-chat)
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authored by: Corentin Noël <corentin@elementaryos.org>
19 */
20
21public class Audience.Widgets.PlaylistPopover : Gtk.Popover {
22 Gtk.ScrolledWindow playlist_scrolled;
23 public PlaylistPopover () {
24 opacity = GLOBAL_OPACITY;
25 var grid = new Gtk.Grid ();
26 grid.row_spacing = 6;
27 grid.column_spacing = 12;
28 grid.margin = 6;
29
30 var fil = new Gtk.Button.with_label (_("Add from Harddrive…"));
31 fil.image = new Gtk.Image.from_icon_name ("document-open", Gtk.IconSize.DIALOG);
32 var dvd = new Gtk.Button.with_label (_("Play a DVD…"));
33 dvd.image = new Gtk.Image.from_icon_name ("media-cdrom", Gtk.IconSize.DIALOG);
34 dvd.no_show_all = true;
35 var net = new Gtk.Button.with_label (_("Network File…"));
36 net.image = new Gtk.Image.from_icon_name ("internet-web-browser", Gtk.IconSize.DIALOG);
37
38 playlist_scrolled = new Gtk.ScrolledWindow (null, null);
39 var app = ((Audience.App) GLib.Application.get_default ());
40 playlist_scrolled.add (app.playlist);
41
42 fil.clicked.connect ( () => {
43 hide ();
44 app.run_open_file ();
45 });
46
47 dvd.clicked.connect ( () => {
48 hide ();
49 app.run_open_dvd ();
50 });
51
52 net.clicked.connect ( () => {
53 /*var entry = new Gtk.Entry ();
54 entry.secondary_icon_stock = Gtk.Stock.OPEN;
55 entry.icon_release.connect ( (pos, e) => {
56 open_file (entry.text);
57 video_player.playing = true;
58 pop.destroy ();
59 });
60 box.remove (net);
61 box.reorder_child (entry, 2);
62 entry.show ();*/
63 });
64
65 grid.attach (playlist_scrolled, 0, 0, 2, 1);
66 grid.attach (fil, 0, 1, 1, 1);
67 grid.attach (dvd, 1, 1, 1, 1);
68
69 //look for dvd
70 var disk_manager = DiskManager.get_default ();
71 foreach (var volume in disk_manager.get_volumes ()) {
72 dvd.no_show_all = false;
73 dvd.show ();
74 }
75
76 disk_manager.volume_found.connect ((vol) => {
77 dvd.no_show_all = false;
78 dvd.show ();
79 });
80
81 disk_manager.volume_removed.connect ((vol) => {
82 if (disk_manager.get_volumes ().length () <= 0) {
83 dvd.no_show_all = true;
84 dvd.hide ();
85 }
86 });
87
88 //grid.add (net);
89 add (grid);
90 }
91
92 //Override because the Popover doesn't auto-rejust his size.
93 public override void get_preferred_height (out int minimum_height, out int natural_height) {
94 base.get_preferred_height (out minimum_height, out natural_height);
95 int p_minimum_height;
96 int p_natural_height;
97 var app = ((Audience.App) GLib.Application.get_default ());
98 app.playlist.get_preferred_height (out p_minimum_height, out p_natural_height);
99 int temp_minimum_height = minimum_height + p_minimum_height;
100 int r_minimum_height;
101 int r_natural_height;
102 relative_to.get_preferred_height (out r_minimum_height, out r_natural_height);
103 if (temp_minimum_height < app.mainwindow.get_window ().get_height () - r_minimum_height*2) {
104 minimum_height = temp_minimum_height;
105 } else {
106 minimum_height = app.mainwindow.get_window ().get_height () - r_minimum_height*2;
107 }
108
109 int temp_natural_height = natural_height + p_natural_height;
110 if (temp_natural_height < app.mainwindow.get_window ().get_height () - r_natural_height*2) {
111 natural_height = temp_natural_height;
112 } else {
113 natural_height = minimum_height;
114 }
115 }
116}
0\ No newline at end of file117\ No newline at end of file
1118
=== added file 'src/Widgets/PreviewPopover.vala'
--- src/Widgets/PreviewPopover.vala 1970-01-01 00:00:00 +0000
+++ src/Widgets/PreviewPopover.vala 2014-07-06 11:18:29 +0000
@@ -0,0 +1,90 @@
1// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
2/*-
3 * Copyright (c) 2013-2014 Audience Developers (http://launchpad.net/pantheon-chat)
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authored by: Corentin Noël <corentin@elementaryos.org>
19 */
20
21public class Audience.Widgets.PreviewPopover : Gtk.Popover {
22 public Clutter.Actor preview_actor;
23 dynamic Gst.Element preview_playbin;
24 Clutter.Texture video;
25 double ratio = 0;
26 public PreviewPopover () {
27 opacity = GLOBAL_OPACITY;
28 can_focus = false;
29 sensitive = false;
30 modal = false;
31
32 // connect gstreamer stuff
33 preview_playbin = Gst.ElementFactory.make ("playbin", "play");
34 preview_playbin.get_bus ().add_signal_watch ();
35 preview_playbin.get_bus ().message.connect ((msg) => {
36 switch (msg.type) {
37 case Gst.MessageType.STATE_CHANGED:
38 break;
39 case Gst.MessageType.ASYNC_DONE:
40 break;
41 }
42 });
43 video = new Clutter.Texture ();
44
45 dynamic Gst.Element video_sink = Gst.ElementFactory.make ("cluttersink", "source");
46 video_sink.texture = video;
47 preview_playbin.video_sink = video_sink;
48 var clutter = new GtkClutter.Embed ();
49 clutter.margin = 6;
50 var stage = (Clutter.Stage)clutter.get_stage ();
51 stage.background_color = {0, 0, 0, 0};
52 stage.use_alpha = true;
53
54 video.add_constraint (new Clutter.BindConstraint (stage, Clutter.BindCoordinate.WIDTH, 0));
55 video.add_constraint (new Clutter.BindConstraint (stage, Clutter.BindCoordinate.HEIGHT, 0));
56
57 stage.add_child (video);
58 add (clutter);
59 //show_all ();
60 closed.connect (() => {preview_playbin.set_state (Gst.State.PAUSED);});
61 }
62
63 public void set_preview_uri (string uri) {
64 preview_playbin.set_state (Gst.State.READY);
65 preview_playbin.uri = uri;
66 preview_playbin.volume = 0.0;
67
68 try {
69 var info = new Gst.PbUtils.Discoverer (10 * Gst.SECOND).discover_uri (uri);
70 var video = info.get_video_streams ();
71 if (video.data != null) {
72 var video_info = (Gst.PbUtils.DiscovererVideoInfo)video.data;
73 uint video_width = video_info.get_width ();
74 uint video_height = video_info.get_height ();
75 ratio = ((double) video_height) / ((double) video_width);
76 set_size_request (200, (int) (ratio*200));
77 }
78 } catch (Error e) {
79 warning (e.message);
80 return;
81 }
82 }
83
84 public void set_preview_progress (double progress) {
85 int64 length;
86 preview_playbin.query_duration (Gst.Format.TIME, out length);
87 preview_playbin.seek_simple (Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.ACCURATE, (int64)(double.max (progress, 0.0) * length));
88 preview_playbin.set_state (Gst.State.PLAYING);
89 }
90}
0\ No newline at end of file91\ No newline at end of file
192
=== added file 'src/Widgets/SettingsPopover.vala'
--- src/Widgets/SettingsPopover.vala 1970-01-01 00:00:00 +0000
+++ src/Widgets/SettingsPopover.vala 2014-07-06 11:18:29 +0000
@@ -0,0 +1,166 @@
1// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
2/*-
3 * Copyright (c) 2013-2014 Audience Developers (http://launchpad.net/pantheon-chat)
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authored by: Corentin Noël <corentin@elementaryos.org>
19 */
20
21public class Audience.Widgets.SettingsPopover : Gtk.Popover {
22 private Gtk.ComboBoxText languages;
23 private Gtk.ComboBoxText subtitles;
24 private Gtk.FileChooserButton external_subtitle_file;
25
26 public SettingsPopover () {
27 opacity = GLOBAL_OPACITY;
28
29 languages = new Gtk.ComboBoxText ();
30 subtitles = new Gtk.ComboBoxText ();
31 external_subtitle_file = new Gtk.FileChooserButton (_("External Subtitles"), Gtk.FileChooserAction.OPEN);
32
33 var lang_label = new Gtk.Label (_("Audio:"));
34 lang_label.halign = Gtk.Align.END;
35
36 var sub_label = new Gtk.Label (_("Subtitles:"));
37 sub_label.halign = Gtk.Align.END;
38
39 var sub_ext_label = new Gtk.Label (_("External Subtitles:"));
40 sub_ext_label.halign = Gtk.Align.END;
41
42 var setupgrid = new Gtk.Grid ();
43 setupgrid.row_spacing = 6;
44 setupgrid.margin = 6;
45 setupgrid.attach (lang_label, 0, 1, 1, 1);
46 setupgrid.attach (languages, 1, 1, 1, 1);
47 setupgrid.attach (sub_label, 0, 2, 1, 1);
48 setupgrid.attach (subtitles, 1, 2, 1, 1);
49 setupgrid.attach (sub_ext_label, 0, 3, 1, 1);
50 setupgrid.attach (external_subtitle_file, 1, 3, 1, 1);
51 setupgrid.column_homogeneous = true;
52 setupgrid.column_spacing = 12;
53
54 external_subtitle_file.file_set.connect (() => {
55 VideoPlayer.get_default ().set_subtitle_uri (external_subtitle_file.get_uri ());
56 });
57
58 VideoPlayer.get_default ().external_subtitle_changed.connect ((uri) => {
59 external_subtitle_file.select_uri (uri);
60 });
61
62 subtitles.changed.connect (() => {
63 if (subtitles.active_id == null)
64 return;
65
66 var id = int.parse (subtitles.active_id);
67 VideoPlayer.get_default ().current_text = id;
68 });
69
70 languages.changed.connect ( () => { //place it here to not get problems
71 if (languages.active_id == null)
72 return;
73
74 VideoPlayer.get_default ().current_audio = int.parse (languages.active_id);
75 });
76
77 add (setupgrid);
78 }
79
80 public void setup_text () {
81 subtitles.sensitive = false;
82 if (subtitles.model.iter_n_children (null) > 0)
83 subtitles.remove_all ();
84
85 int n_text;
86 VideoPlayer.get_default ().playbin.get ("n-text", out n_text);
87 for (var i=0; i<n_text; i++) {
88 Gst.TagList tags = null;
89 Signal.emit_by_name (VideoPlayer.get_default ().playbin, "get-text-tags", i, out tags);
90 if (tags == null)
91 continue;
92
93 string desc;
94 string readable = null;
95 tags.get_string (Gst.Tags.LANGUAGE_CODE, out desc);
96 if (desc == null)
97 tags.get_string (Gst.Tags.CODEC, out desc);
98
99 if (desc != null) {
100 readable = Gst.Tag.get_language_name (desc);
101 var language = Gst.Tag.get_language_name (desc);
102 subtitles.append (i.to_string (), language == null ? desc : language);
103 subtitles.sensitive = true;
104 }
105 }
106
107 subtitles.append ("-1", _("None"));
108 subtitles.active_id = VideoPlayer.get_default ().current_text.to_string ();
109 }
110
111 public void setup_audio () {
112 languages.sensitive = false;
113 if (languages.model.iter_n_children (null) > 0)
114 languages.remove_all ();
115
116 int n_audio;
117 VideoPlayer.get_default ().playbin.get ("n-audio", out n_audio);
118 for (var i=0; i<n_audio; i++) {
119 Gst.TagList tags = null;
120 Signal.emit_by_name (VideoPlayer.get_default ().playbin, "get-audio-tags", i, out tags);
121 if (tags == null)
122 continue;
123
124 string desc;
125 string readable = null;
126 tags.get_string (Gst.Tags.LANGUAGE_CODE, out desc);
127 if (desc == null)
128 tags.get_string (Gst.Tags.CODEC, out desc);
129
130 if (desc != null) {
131 readable = Gst.Tag.get_language_name (desc);
132 languages.append (i.to_string (), readable == null ? desc : readable);
133 languages.sensitive = true;
134 }
135 }
136
137 if (languages.model.iter_n_children (null) <= 0) {
138 languages.append ("def", _("Default"));
139 languages.active = 0;
140 } else {
141 languages.active_id = VideoPlayer.get_default ().current_audio.to_string ();
142 }
143 }
144
145 public void next_audio () {
146 int current = int.parse (languages.active_id);
147 if (current < languages.model.iter_n_children (null) - 1) {
148 current++;
149 } else {
150 current = 0;
151 }
152
153 languages.active_id = current.to_string ();
154 }
155
156 public void next_text () {
157 int current = int.parse (subtitles.active_id);
158 if (current < subtitles.model.iter_n_children (null)) {
159 current++;
160 } else {
161 current = 0;
162 }
163
164 subtitles.active_id = current.to_string ();
165 }
166}
0\ No newline at end of file167\ No newline at end of file
1168
=== removed file 'src/Widgets/TagView.vala'
--- src/Widgets/TagView.vala 2014-05-15 07:10:20 +0000
+++ src/Widgets/TagView.vala 1970-01-01 00:00:00 +0000
@@ -1,253 +0,0 @@
1
2/*
3 The panel on the right hand side
4*/
5
6public const string LIGHT_WINDOW_STYLE = """
7 .content-view-window {
8 background-image:none;
9 background-color:@bg_color;
10
11 border-radius: 6px;
12
13 border-width:1px;
14 border-style: solid;
15 border-color: alpha (#000, 0.25);
16 }
17""";
18
19namespace Audience.Widgets
20{
21 public class TagView : GtkClutter.Actor
22 {
23 public bool expanded;
24 public Gtk.Grid taggrid;
25 public Audience.App app;
26
27 public Gtk.ComboBoxText languages;
28 public Gtk.ComboBoxText subtitles;
29 private Gtk.FileChooserButton external_subtitle_file;
30
31 private Granite.Drawing.BufferSurface buffer;
32 int shadow_blur = 30;
33 int shadow_x = 0;
34 int shadow_y = 0;
35 double shadow_alpha = 0.5;
36
37 bool currently_parsing = false;
38
39 public signal void select_external_subtitle (string uri);
40
41 public TagView (Audience.App app) {
42 this.app = app;
43 this.reactive = true;
44 this.buffer = new Granite.Drawing.BufferSurface (100, 100);
45
46 var notebook = new Granite.Widgets.StaticNotebook (false);
47
48 /*tags*/
49 var tagview = new Gtk.ScrolledWindow (null, null);
50 taggrid = new Gtk.Grid ();
51 taggrid.column_spacing = 10;
52 taggrid.margin = 12;
53 tagview.add_with_viewport (taggrid);
54
55 /*setup*/
56 var setupgrid = new Gtk.Grid ();
57 this.languages = new Gtk.ComboBoxText ();
58 this.subtitles = new Gtk.ComboBoxText ();
59 this.external_subtitle_file = new Gtk.FileChooserButton (_("External Subtitles"), Gtk.FileChooserAction.OPEN);
60 var lang_lbl = new LLabel.right (_("Audio")+":");
61 var sub_lbl = new LLabel.right (_("Subtitles")+":");
62 var sub_ext_lbl = new LLabel.right (_("External Subtitles") + ":");
63 setupgrid.attach (lang_lbl, 0, 1, 1, 1);
64 setupgrid.attach (languages, 1, 1, 1, 1);
65 setupgrid.attach (sub_lbl, 0, 2, 1, 1);
66 setupgrid.attach (subtitles, 1, 2, 1, 1);
67 setupgrid.attach (sub_ext_lbl, 0, 3, 1, 1);
68 setupgrid.attach (this.external_subtitle_file, 1, 3, 1, 1);
69 setupgrid.column_homogeneous = true;
70 setupgrid.margin = 12;
71 setupgrid.column_spacing = 12;
72
73 external_subtitle_file.file_set.connect (() => {
74 select_external_subtitle (external_subtitle_file.get_uri ());
75 });
76 app.video_player.external_subtitle_changed.connect ( (uri) => {
77 external_subtitle_file.set_uri (uri);
78 });
79 this.subtitles.changed.connect ( () => {
80 if (subtitles.active_id == null || currently_parsing)
81 return;
82 var id = int.parse (this.subtitles.active_id);
83 app.video_player.current_text = id;
84 });
85
86 languages.changed.connect ( () => { //place it here to not get problems
87 if (languages.active_id == null || currently_parsing)
88 return;
89 app.video_player.current_audio = int.parse (this.languages.active_id);
90 });
91
92 var playlist_scrolled = new Gtk.ScrolledWindow (null, null);
93 playlist_scrolled.add (this.app.playlist);
94
95 notebook.append_page (playlist_scrolled, new Gtk.Label (_("Playlist")));
96 notebook.append_page (setupgrid, new Gtk.Label (_("Options")));
97
98 /*draw the window stylish!*/
99 var css = new Gtk.CssProvider ();
100 try {
101 css.load_from_data (LIGHT_WINDOW_STYLE, -1);
102 } catch (Error e) { warning (e.message); }
103
104 var draw_ref = new Gtk.Window ();
105 draw_ref.get_style_context ().add_class ("content-view-window");
106 draw_ref.get_style_context ().add_provider (css, Gtk.STYLE_PROVIDER_PRIORITY_FALLBACK);
107
108 var w = -1; var h = -1;
109 this.get_widget ().size_allocate.connect ( () => {
110 if (w == this.get_widget ().get_allocated_width () &&
111 h == this.get_widget ().get_allocated_height ())
112 return;
113 w = this.get_widget ().get_allocated_width ();
114 h = this.get_widget ().get_allocated_height ();
115
116 this.buffer = new Granite.Drawing.BufferSurface (w, h);
117
118 this.buffer.context.rectangle (shadow_blur + shadow_x,
119 shadow_blur + shadow_y, w - shadow_blur*2 + shadow_x, h - shadow_blur*2 + shadow_y);
120 this.buffer.context.set_source_rgba (0, 0, 0, shadow_alpha);
121 this.buffer.context.fill ();
122 this.buffer.exponential_blur (shadow_blur / 2);
123
124 draw_ref.get_style_context ().render_activity (this.buffer.context,
125 shadow_blur + shadow_x, shadow_blur + shadow_y,
126 w - shadow_blur*2 + shadow_x, h - shadow_blur*2 + shadow_y);
127 });
128 this.get_widget ().draw.connect ( (ctx) => {
129 ctx.set_operator (Cairo.Operator.SOURCE);
130 ctx.rectangle (0, 0, this.width, this.height);
131 ctx.set_source_rgba (0.0, 0.0, 0.0, 0.0);
132 ctx.fill ();
133
134 ctx.set_source_surface (this.buffer.surface, 0, 0);
135 ctx.paint ();
136
137 return false;
138 });
139
140 var no_bg = new Gtk.CssProvider ();
141 try {
142 no_bg.load_from_data ("""
143 * {
144 background-color: alpha(#fff, 0);
145 }
146 .view:selected:focused {
147 color: @selected_bg_color;
148 }
149 """, -1);
150 } catch (Error e) { warning (e.message); }
151 setupgrid.get_parent ().get_style_context ().add_provider (no_bg, 20000);
152 app.playlist.get_style_context ().add_provider (no_bg, 20000);
153
154 playlist_scrolled.margin = 3;
155 notebook.margin = shadow_blur + 2;
156 notebook.margin_top += 3;
157 this.get_widget ().get_style_context ().add_class ("content-view");
158 ((Gtk.Bin)this.get_widget ()).add (notebook);
159 this.get_widget ().show_all ();
160 this.width = 350;
161 this.opacity = 0;
162 this.expanded = false;
163 }
164
165 public override void allocate (Clutter.ActorBox box, Clutter.AllocationFlags flags) {
166 //have a minimum height in order to not get the negative allocation warnings
167 if (box.y2 - box.y1 < 100) {
168 box.y2 = box.y1 + 100;
169 }
170 base.allocate (box, flags);
171 }
172
173 public void expand (){
174 //make sure it comes from right bounds
175 x = get_stage ().width + 100;
176
177 var x2 = this.get_stage ().width - this.width + 10;
178 this.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 400, x:x2);
179 this.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 400, opacity:255);
180 this.expanded = true;
181 }
182
183 public void collapse (){
184 var x2 = this.get_stage ().width;
185 this.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 400, x:x2);
186 this.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 400, opacity:0);
187 this.expanded = false;
188 }
189
190 public void setup_text_setup () { setup_setup ("text"); }
191 public void setup_audio_setup () { setup_setup ("audio"); }
192 /*target is either "text" or "audio"*/
193 public void setup_setup (string target) {
194 currently_parsing = true;
195
196 if (target == "audio" && languages.model.iter_n_children (null) > 0)
197 languages.remove_all ();
198 else if (target == "text" && subtitles.model.iter_n_children (null) > 0)
199 subtitles.remove_all ();
200
201 Value num = 0;
202 app.video_player.playbin.get_property ("n-"+target, ref num);
203
204 int used = 0;
205 for (var i=0;i<num.get_int ();i++) {
206 Gst.TagList tags = null;
207 Signal.emit_by_name (app.video_player.playbin, "get-"+target+"-tags", i, out tags);
208 if (tags == null)
209 continue;
210
211 string desc;
212 string readable = null;
213 tags.get_string (Gst.Tags.LANGUAGE_CODE, out desc);
214 if (desc == null)
215 tags.get_string (Gst.Tags.CODEC, out desc);
216
217 if (desc != null)
218 readable = Gst.Tag.get_language_name (desc);
219
220 if (target == "audio" && desc != null) {
221 this.languages.append (i.to_string (), readable == null ? desc : readable);
222 used ++;
223 } else if (desc != null) {
224 var language = Gst.Tag.get_language_name (desc);
225 this.subtitles.append (i.to_string (), language == null ? desc : language);
226 used ++;
227 }
228 }
229
230 if (target == "audio") {
231
232 if (used == 0) {
233 languages.append ("def", _("Default"));
234 languages.active = 0;
235 languages.sensitive = false;
236 } else {
237 languages.sensitive = true;
238 languages.active_id = app.video_player.current_audio.to_string ();
239 }
240 } else {
241 if (used == 0)
242 subtitles.sensitive = false;
243 else
244 subtitles.sensitive = true;
245
246 subtitles.append ("-1", _("None"));
247 subtitles.active_id = app.video_player.current_text.to_string ();
248 }
249
250 currently_parsing = false;
251 }
252 }
253}
2540
=== added file 'src/Widgets/TimeWidget.vala'
--- src/Widgets/TimeWidget.vala 1970-01-01 00:00:00 +0000
+++ src/Widgets/TimeWidget.vala 2014-07-06 11:18:29 +0000
@@ -0,0 +1,127 @@
1// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
2/*-
3 * Copyright (c) 2013-2014 Audience Developers (http://launchpad.net/pantheon-chat)
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authored by: Tom Beckmann <tomjonabc@gmail.com>
19 * Corentin Noël <corentin@elementaryos.org>
20 */
21
22public class Audience.Widgets.TimeWidget : Gtk.Grid {
23 public signal void slider_motion_event (Gdk.EventMotion event);
24
25 public Gtk.Label progression_label;
26 public Gtk.Label time_label;
27 public Gtk.Scale scale;
28 public signal void seeked (double val);
29 private Audience.Widgets.PreviewPopover preview_popover;
30 private bool is_seeking = false;
31 private bool released = true;
32 private uint timeout_id = 0;
33 private int original = 0;
34
35 public TimeWidget () {
36 orientation = Gtk.Orientation.HORIZONTAL;
37 column_spacing = 12;
38 halign = Gtk.Align.CENTER;
39 progression_label = new Gtk.Label ("");
40 time_label = new Gtk.Label ("");
41
42 scale = new Gtk.Scale.with_range (Gtk.Orientation.HORIZONTAL, 0, 1, 0.1);
43 scale.expand = true;
44 scale.draw_value = false;
45 scale.can_focus = false;
46 scale.events |= Gdk.EventMask.POINTER_MOTION_MASK;
47 scale.events |= Gdk.EventMask.LEAVE_NOTIFY_MASK;
48 scale.events |= Gdk.EventMask.ENTER_NOTIFY_MASK;
49 scale.button_press_event.connect ((event) => {
50 is_seeking = true;
51 released = false;
52
53 if (timeout_id != 0)
54 Source.remove (timeout_id);
55
56 timeout_id = Timeout.add (300, () => {
57 if (released == false)
58 return true;
59 seeked (scale.get_value ());
60 is_seeking = false;
61
62 timeout_id = 0;
63
64 return false;
65 });
66
67 return false;
68 });
69
70 scale.enter_notify_event.connect ((event) => {
71 preview_popover.show_all ();
72 return false;
73 });
74
75 scale.leave_notify_event.connect ((event) => {
76 preview_popover.hide ();
77 return false;
78 });
79
80 // XXX: Store the original size because the popover doesn't update his x=0 position when resizing.
81 scale.motion_notify_event.connect ((event) => {
82 if (original == 0)
83 original = event.window.get_width ();
84
85 var pointing = preview_popover.pointing_to;
86 var distance = original - event.window.get_width ();
87 pointing.x = (int)(event.x) - event.window.get_width ()/2 - distance/2;
88 preview_popover.set_pointing_to ((Gdk.Rectangle)pointing);
89 preview_popover.set_preview_progress (((double)event.x)/((double)event.window.get_width ()));
90
91 slider_motion_event (event);
92
93 return false;
94 });
95
96 scale.button_release_event.connect ((event) => {released = true; return false;});
97 preview_popover = new Audience.Widgets.PreviewPopover ();
98 preview_popover.relative_to = this;
99
100 add (progression_label);
101 add (scale);
102 add (time_label);
103 }
104
105 public void set_preview_uri (string uri) {
106 preview_popover.set_preview_uri (uri);
107 }
108
109 public override void get_preferred_width (out int minimum_width, out int natural_width) {
110 base.get_preferred_width (out minimum_width, out natural_width);
111
112 if (parent.get_window () == null)
113 return;
114 var width = parent.get_window ().get_width ();
115 if (width > 0 && width >= minimum_width) {
116 natural_width = width;
117 }
118 }
119
120 public void set_progression_time (double current_time, double total_time) {
121 if (is_seeking == true)
122 return;
123 scale.set_value (current_time/total_time);
124 progression_label.label = seconds_to_time ((int)(current_time / 1000000000));
125 time_label.label = seconds_to_time ((int)((total_time - current_time) / 1000000000));
126 }
127}
0\ No newline at end of file128\ No newline at end of file
1129
=== removed file 'src/Widgets/TopPanel.vala'
--- src/Widgets/TopPanel.vala 2013-05-19 17:10:26 +0000
+++ src/Widgets/TopPanel.vala 1970-01-01 00:00:00 +0000
@@ -1,87 +0,0 @@
1
2namespace Audience.Widgets{
3
4 /*a bar only shown for fullscreen including volume and unfullscreen*/
5 public class TopPanel : Clutter.Box {
6
7 public Button exit;
8 public GtkClutter.Actor volume;
9 public Gtk.VolumeButton vol;
10
11 bool _hidden;
12 public bool hidden{
13 get { return _hidden; }
14 set {
15 if (_hidden && !value){
16 this.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 400, y : 0.0f);
17 }else if (!_hidden && value){
18 this.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 1000, y : -this.height);
19 }
20 this._hidden = value;
21 }
22 }
23
24 public signal void unfullscreen ();
25
26 public TopPanel () {
27 layout_manager = new Clutter.BoxLayout ();
28
29 this.exit = new Button ("view-restore-symbolic", Gtk.Stock.LEAVE_FULLSCREEN);
30 this.volume = new GtkClutter.Actor ();
31 var buf = new Clutter.Rectangle.with_color ({0,0,0,0});
32 this.vol = new Gtk.VolumeButton ();
33 this.vol.use_symbolic = true;
34 this._hidden = true;
35
36 exit.reactive = true;
37 exit.y = 2;
38 exit.button_release_event.connect ((e) => {
39 unfullscreen ();
40 return true;
41 });
42
43 var css = new Gtk.CssProvider ();
44 try {
45 css.load_from_data ("""
46 * {
47 color: #fff;
48 transition: 2ms linear;
49 }
50 *:hover {
51 color: #aaa;
52 transition: 2ms linear;
53 }
54 .button {
55 background-image: none;
56 background-color: alpha (#000, 0);
57 border-color: alpha (#000, 0);
58 border-image: none;
59 -unico-border-gradient: none;
60 -unico-inner-stroke-width: 0px;
61 -unico-outer-stroke-width: 0px;
62 }
63 """, -1);
64 }catch (Error e) { warning (e.message); }
65 this.vol.get_child ().get_style_context ().add_provider (css, 20000);
66 this.vol.get_style_context ().add_provider (css, 20000);
67
68 ((Gtk.Container)this.volume.get_widget ()).add (this.vol);
69 this.volume.get_widget ().draw.connect ( (ctx) => {
70 ctx.rectangle (0, 0, this.volume.width, this.volume.height);
71 ctx.set_operator (Cairo.Operator.SOURCE);
72 ctx.set_source_rgba (0, 0, 0, 0);
73 ctx.fill ();
74 return false;
75 });
76
77 buf.width = 10;
78
79 //this.add_child (this.volume); removed until we get it to control global volume
80 this.add_child (buf);
81 this.add_child (this.exit);
82
83 y = -height;
84 }
85 }
86}
87
880
=== modified file 'src/Widgets/VideoPlayer.vala'
--- src/Widgets/VideoPlayer.vala 2014-05-15 07:10:20 +0000
+++ src/Widgets/VideoPlayer.vala 2014-07-06 11:18:29 +0000
@@ -1,3 +1,24 @@
1// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
2/*-
3 * Copyright (c) 2013-2014 Audience Developers (http://launchpad.net/pantheon-chat)
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authored by: Tom Beckmann <tomjonabc@gmail.com>
19 * Corentin Noël <corentin@elementaryos.org>
20 */
21
1using Clutter;22using Clutter;
223
3enum PlayFlags {24enum PlayFlags {
@@ -14,14 +35,17 @@
14 SOFT_COLORBALANCE = (1 << 10)35 SOFT_COLORBALANCE = (1 << 10)
15}36}
1637
17namespace Audience.Widgets38namespace Audience.Widgets {
18{39 public class VideoPlayer : Actor {
19 public class VideoPlayer : Actor40 private static VideoPlayer? video_player = null;
20 {41 public static VideoPlayer get_default () {
21 42 if (video_player == null)
43 video_player = new VideoPlayer ();
44 return video_player;
45 }
46
22 public bool at_end;47 public bool at_end;
23 48
24 bool paused;
25 bool _playing;49 bool _playing;
26 public bool playing {50 public bool playing {
27 get {51 get {
@@ -30,47 +54,31 @@
30 set {54 set {
31 if (value == playing)55 if (value == playing)
32 return;56 return;
33
34 controls.show_play_button (!value);
35
36 playbin.set_state (value ? Gst.State.PLAYING : Gst.State.PAUSED);
3757
38 set_screensaver (!value);58 set_screensaver (!value);
39 set_screenlock (!value);59 set_screenlock (!value);
4060 playbin.set_state (value ? Gst.State.PLAYING : Gst.State.PAUSED);
41 if (!value) {
42 paused = true;
43 lock_hide ();
44 }
45 if (value && paused) {
46 paused = false;
47 unlock_hide ();
48 }
49
50 _playing = value;61 _playing = value;
51 }62 }
52 }63 }
53 64
54 public double progress {65 public double progress {
55 get {66 get {
56 int64 length, prog;67 int64 length, prog;
57
58 playbin.query_duration (Gst.Format.TIME, out length);68 playbin.query_duration (Gst.Format.TIME, out length);
59 playbin.query_position (Gst.Format.TIME, out prog);69 playbin.query_position (Gst.Format.TIME, out prog);
60
61 if (length == 0)70 if (length == 0)
62 return 0;71 return 0;
63 72
64 return prog / (double)length;73 return prog / (double)length;
65 }74 }
66 set {75 set {
67 int64 length;76 int64 length;
68 playbin.query_duration (Gst.Format.TIME, out length);77 playbin.query_duration (Gst.Format.TIME, out length);
69 playbin.seek_simple (Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.ACCURATE,78 playbin.seek_simple (Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.ACCURATE, (int64)(double.max (value, 0.0) * length));
70 (int64)(double.max (value, 0.0) * length));
71 }79 }
72 }80 }
73 81
74 public double volume {82 public double volume {
75 get {83 get {
76 return playbin.volume;84 return playbin.volume;
@@ -79,7 +87,7 @@
79 playbin.volume = value;87 playbin.volume = value;
80 }88 }
81 }89 }
82 90
83 public string uri {91 public string uri {
84 owned get {92 owned get {
85 return playbin.current_uri;93 return playbin.current_uri;
@@ -101,38 +109,20 @@
101 warning (e.message);109 warning (e.message);
102 return;110 return;
103 }111 }
104 112
105 intial_relayout = true;113 intial_relayout = true;
106
107 playing = false;114 playing = false;
108 playbin.set_state (Gst.State.READY);115 playbin.set_state (Gst.State.READY);
109 playbin.suburi = null;116 playbin.suburi = null;
110 subtitle_uri = null;117 subtitle_uri = null;
111 playbin.uri = value;118 playbin.uri = value;
112 volume = 1.0;119 volume = 1.0;
113 controls.slider.set_preview_uri (value);
114 at_end = false;120 at_end = false;
115 121
116 relayout ();122 relayout ();
117 playing = true;123 playing = true;
118 }124 }
119 }125 }
120
121 bool _controls_hidden;
122 public bool controls_hidden
123 {
124 get { return _controls_hidden; }
125 set {
126 if (_controls_hidden && !value) {
127 float y2 = get_stage ().height - controls.height;
128 controls.animate (Clutter.AnimationMode.EASE_OUT_CUBIC, 300, y:y2);
129 } else if (!_controls_hidden && value){
130 float y2 = get_stage ().height;
131 controls.animate (Clutter.AnimationMode.EASE_IN_QUAD, 600, y:y2);
132 }
133 _controls_hidden = value;
134 }
135 }
136126
137 public int current_audio {127 public int current_audio {
138 get {128 get {
@@ -167,161 +157,73 @@
167 }157 }
168 }158 }
169 }159 }
170 160
171 public dynamic Gst.Element playbin;161 public dynamic Gst.Element playbin;
172 Clutter.Texture video;162 Clutter.Texture video;
173 Controls controls;
174 TopPanel panel;
175163
176 uint video_width;164 uint video_width;
177 uint video_height;165 uint video_height;
178 166
179 // we will only hide if hide lock is 0
180 public int hide_lock = 0;
181
182 uint hiding_timer;
183
184 public GnomeSessionManager session_manager;167 public GnomeSessionManager session_manager;
185 uint32 inhibit_cookie;168 uint32 inhibit_cookie;
186 169
187 public bool fullscreened { get; set; }
188
189 public signal void ended ();170 public signal void ended ();
190 public signal void toggle_side_pane (bool show);171 public signal void toggle_side_pane (bool show);
191 public signal void text_tags_changed ();172 public signal void text_tags_changed ();
192 public signal void audio_tags_changed ();173 public signal void audio_tags_changed ();
193 public signal void show_open_context ();
194 public signal void exit_fullscreen ();
195 public signal void error ();174 public signal void error ();
196 public signal void plugin_install_done ();175 public signal void plugin_install_done ();
197 public signal void configure_window (uint video_w, uint video_h);176 public signal void configure_window (uint video_w, uint video_h);
177 public signal void progression_changed (double current_time, double total_time);
198 public signal void external_subtitle_changed (string? uri);178 public signal void external_subtitle_changed (string? uri);
199 179
200 public VideoPlayer ()180 private VideoPlayer () {
201 {
202 reactive = true;
203
204 controls = new Controls ();
205 controls.add_constraint (new BindConstraint (this, BindCoordinate.WIDTH, 0));
206 controls.slider.preview.add_constraint (new BindConstraint (controls, Clutter.BindCoordinate.Y, -105.0f));
207
208 panel = new TopPanel ();
209
210 video = new Clutter.Texture ();181 video = new Clutter.Texture ();
211 video.reactive = true;182
212 183 dynamic Gst.Element video_sink = Gst.ElementFactory.make ("cluttersink", "source");
184 video_sink.texture = video;
185
213 playbin = Gst.ElementFactory.make ("playbin", "playbin");186 playbin = Gst.ElementFactory.make ("playbin", "playbin");
214 var video_sink = Audience.get_clutter_sink ();
215 video_sink.texture = video;
216
217 playbin.video_sink = video_sink;187 playbin.video_sink = video_sink;
218 188
219 add_child (video);189 add_child (video);
220 add_child (controls);
221 add_child (panel);
222 add_child (controls.slider.preview);
223
224 controls.slider.seeked.connect ( (v) => {
225 debug ("Seeked to %f", v);
226 progress = v;
227 });
228 Timeout.add (100, () => {190 Timeout.add (100, () => {
229 int64 length, prog;191 int64 length, prog;
230 playbin.query_position (Gst.Format.TIME, out prog);192 playbin.query_position (Gst.Format.TIME, out prog);
231 playbin.query_duration (Gst.Format.TIME, out length);193 playbin.query_duration (Gst.Format.TIME, out length);
232
233 if (length == 0)194 if (length == 0)
234 return true;195 return true;
235 196
236 controls.slider.progress = prog / (double)length;197 progression_changed ((double)prog, (double)length);
237
238 controls.current.text = seconds_to_time ((int)(prog / 1000000000));
239 controls.remaining.text = "-" + seconds_to_time ((int)(length / 1000000000) - (int)(prog / 1000000000));
240
241 return true;198 return true;
242 });199 });
200
243 playbin.about_to_finish.connect (() => {201 playbin.about_to_finish.connect (() => {
244 at_end = true;202 at_end = true;
245 ended ();203 ended ();
246 });204 });
247205
248 notify["fullscreened"].connect (() => {
249 if (hide_lock > 0)
250 panel.hidden = !fullscreened;
251 });
252 panel.unfullscreen.connect (() => {
253 exit_fullscreen ();
254 });
255
256 bool last_state = false;
257 controls.notify["hovered"].connect (() => {
258 if (controls.hovered == last_state)
259 return;
260
261 last_state = controls.hovered;
262
263 if (controls.hovered)
264 lock_hide ();
265 else
266 unlock_hide ();
267 });
268
269 controls.open.clicked.connect (() => {
270 show_open_context ();
271 });
272 controls.play.clicked.connect (() => playing = !playing );
273 controls.view.clicked.connect (() => {
274 if (!controls.showing_view) {
275 toggle_side_pane (true);
276 controls.view.set_icon ("pane-hide-symbolic", Gtk.Stock.GO_FORWARD, "go-next-symbolic");
277 controls.showing_view = true;
278
279 lock_hide ();
280 } else {
281 toggle_side_pane (false);
282 controls.view.set_icon ("pane-show-symbolic", Gtk.Stock.GO_BACK, "go-previous-symbolic");
283 controls.showing_view = false;
284
285 unlock_hide ();
286 }
287 });
288
289 panel.vol.value_changed.connect ( (value) => {
290 volume = value;
291 });
292 panel.vol.value = 1.0;
293
294 playbin.text_tags_changed.connect ((el) => {206 playbin.text_tags_changed.connect ((el) => {
295 var structure = new Gst.Structure.empty ("tags-changed");207 var structure = new Gst.Structure.empty ("tags-changed");
296 structure.set_value ("type", "text");208 structure.set_value ("type", "text");
297 el.post_message (new Gst.Message.application (el, (owned) structure));209 el.post_message (new Gst.Message.application (el, (owned) structure));
298 });210 });
211
299 playbin.audio_tags_changed.connect ((el) => {212 playbin.audio_tags_changed.connect ((el) => {
300 var structure = new Gst.Structure.empty ("tags-changed");213 var structure = new Gst.Structure.empty ("tags-changed");
301 structure.set_value ("type", "audio");214 structure.set_value ("type", "audio");
302 el.post_message (new Gst.Message.application (el, (owned) structure));215 el.post_message (new Gst.Message.application (el, (owned) structure));
303 });216 });
304 217
305 playbin.get_bus ().add_signal_watch ();218 playbin.get_bus ().add_signal_watch ();
306 playbin.get_bus ().message.connect (watch);219 playbin.get_bus ().message.connect (watch);
307 }220 }
308221
309 public void lock_hide () {
310 if (hide_lock == 0)
311 toggle_controls (true);
312 hide_lock++;
313 }
314 public void unlock_hide () {
315 hide_lock--;
316
317 if (hide_lock < 1)
318 toggle_controls (false);
319 }
320
321 void watch () {222 void watch () {
322 var msg = playbin.get_bus ().peek ();223 var msg = playbin.get_bus ().peek ();
323 if (msg == null)224 if (msg == null)
324 return;225 return;
226
325 switch (msg.type) {227 switch (msg.type) {
326 case Gst.MessageType.APPLICATION:228 case Gst.MessageType.APPLICATION:
327 if (msg.get_structure ().get_name () == "tags-changed") {229 if (msg.get_structure ().get_name () == "tags-changed") {
@@ -374,23 +276,7 @@
374 }276 }
375 }277 }
376278
377 public override bool motion_event (Clutter.MotionEvent event)279 public void set_subtitle_uri (string? uri) {
378 {
379 if (!controls.slider.mouse_grabbed)
380 get_stage ().cursor_visible = true;
381
382 Gst.State state;
383 playbin.get_state (out state, null, 0);
384 if (state == Gst.State.PLAYING) {
385 if (hiding_timer < 1)
386 lock_hide ();
387 set_timeout ();
388 }
389 return true;
390 }
391
392 public void set_subtitle_uri (string? uri)
393 {
394 subtitle_uri = uri;280 subtitle_uri = uri;
395 if (!check_text_layer (subtitle_uri != null)) {281 if (!check_text_layer (subtitle_uri != null)) {
396 apply_subtitles ();282 apply_subtitles ();
@@ -400,8 +286,7 @@
400286
401 // checks whether text layer has to be enabled287 // checks whether text layer has to be enabled
402 // returns if apply_subtitles has been called288 // returns if apply_subtitles has been called
403 bool check_text_layer (bool enable)289 bool check_text_layer (bool enable) {
404 {
405 int flags;290 int flags;
406 playbin.get ("flags", out flags);291 playbin.get ("flags", out flags);
407292
@@ -419,8 +304,7 @@
419 }304 }
420305
421 // ported from totem bvw widget set_subtitle_uri306 // ported from totem bvw widget set_subtitle_uri
422 void apply_subtitles ()307 void apply_subtitles () {
423 {
424 int64 time;308 int64 time;
425 playbin.query_position (Gst.Format.TIME, out time);309 playbin.query_position (Gst.Format.TIME, out time);
426310
@@ -434,7 +318,6 @@
434 }318 }
435319
436 playbin.suburi = subtitle_uri;320 playbin.suburi = subtitle_uri;
437
438 if (current > Gst.State.READY) {321 if (current > Gst.State.READY) {
439 playbin.set_state (current);322 playbin.set_state (current);
440 playbin.get_state (null, null, Gst.CLOCK_TIME_NONE);323 playbin.get_state (null, null, Gst.CLOCK_TIME_NONE);
@@ -451,10 +334,9 @@
451 playbin.get_state (null, null, Gst.CLOCK_TIME_NONE);334 playbin.get_state (null, null, Gst.CLOCK_TIME_NONE);
452 }335 }
453 }336 }
454 337
455 bool intial_relayout = false;338 bool intial_relayout = false;
456 public bool relayout ()339 public bool relayout () {
457 {
458 if (video_width < 1 || video_height < 1 || uri == null)340 if (video_width < 1 || video_height < 1 || uri == null)
459 return false;341 return false;
460342
@@ -464,136 +346,100 @@
464 }346 }
465347
466 var stage = get_stage ();348 var stage = get_stage ();
467
468 var aspect = stage.width / video_width < stage.height / video_height ?349 var aspect = stage.width / video_width < stage.height / video_height ?
469 stage.width / video_width : stage.height / video_height;350 stage.width / video_width : stage.height / video_height;
470 video.width = video_width * aspect;351 video.width = video_width * aspect;
471 video.height = video_height * aspect;352 video.height = video_height * aspect;
472 video.x = (stage.width - video.width) / 2;353 video.x = (stage.width - video.width) / 2;
473 video.y = (stage.height - video.height) / 2;354 video.y = (stage.height - video.height) / 2;
474
475 if (controls.get_animation () != null)
476 controls.detach_animation ();
477 controls.y = controls_hidden ? stage.height : stage.height - controls.height;
478
479 (controls.content as Clutter.Canvas).set_size ((int)controls.width, (int)controls.height);
480 controls.content.invalidate ();
481
482 panel.x = get_stage ().width - panel.width - 10;
483 controls.slider.preview.width = (float) video_width / video_height * controls.slider.preview.height;
484355
485 return true;356 return true;
486 }357 }
487 358
488 void show_error (string? message=null)359 void show_error (string? message=null) {
489 {360 var dlg = new Gtk.Dialog.with_buttons (_("Error"), null, Gtk.DialogFlags.MODAL, _("_OK"), Gtk.ResponseType.OK);
490 var dlg = new Gtk.Dialog.with_buttons (_("Error"), null, Gtk.DialogFlags.MODAL, Gtk.Stock.OK, Gtk.ResponseType.OK);
491 var grid = new Gtk.Grid ();361 var grid = new Gtk.Grid ();
492 var err = new Gtk.Image.from_stock (Gtk.Stock.DIALOG_ERROR, Gtk.IconSize.DIALOG);362 var err = new Gtk.Image.from_icon_name ("dialog-error", Gtk.IconSize.DIALOG);
493
494 err.margin_right = 12;363 err.margin_right = 12;
364
365 var err_label = new Gtk.Label ("");
366 err_label.set_markup ("<b>%s</b>".printf (_("Oops! Audience can't play this file!")));
367
495 grid.margin = 12;368 grid.margin = 12;
496 grid.attach (err, 0, 0, 1, 1);369 grid.attach (err, 0, 0, 1, 1);
497 grid.attach (new Widgets.LLabel.markup ("<b>"+370 grid.attach (err_label, 1, 0, 1, 1);
498 _("Oops! Audience can't play this file!")+"</b>"), 1, 0, 1, 1);
499 if (message != null)371 if (message != null)
500 grid.attach (new Widgets.LLabel (message), 1, 1, 1, 2);372 grid.attach (new Gtk.Label (message), 1, 1, 1, 2);
501373
502 error ();374 error ();
503
504 ((Gtk.Box)dlg.get_content_area ()).add (grid);375 ((Gtk.Box)dlg.get_content_area ()).add (grid);
505 dlg.show_all ();376 dlg.show_all ();
506 dlg.run ();377 dlg.run ();
507 dlg.destroy ();378 dlg.destroy ();
508 }379 }
509 380
510 void handle_missing_plugin (Gst.Message msg)381 void handle_missing_plugin (Gst.Message msg) {
511 {
512 var detail = Gst.PbUtils.missing_plugin_message_get_description (msg);382 var detail = Gst.PbUtils.missing_plugin_message_get_description (msg);
513 var dlg = new Gtk.Dialog.with_buttons ("Missing plugin", null,383 var dlg = new Gtk.Dialog.with_buttons ("Missing plugin", null, Gtk.DialogFlags.MODAL);
514 Gtk.DialogFlags.MODAL);
515 var grid = new Gtk.Grid ();384 var grid = new Gtk.Grid ();
516 var err = new Gtk.Image.from_stock (Gtk.Stock.DIALOG_ERROR, 385 var err = new Gtk.Image.from_icon_name ("dialog-error", Gtk.IconSize.DIALOG);
517 Gtk.IconSize.DIALOG);386 var phrase = new Gtk.Label (_("Some media files need extra software to be played. Audience can install this software automatically."));
518 var phrase = new Widgets.LLabel (_("Some media files need extra software to be played. Audience can install this software automatically."));387
519
520 err.margin_right = 12;388 err.margin_right = 12;
389
390 var err_label = new Gtk.Label ("");
391 err_label.set_markup ("<b>%s</b>".printf (_("Audience needs %s to play this file.").printf (detail)));
392
521 grid.margin = 12;393 grid.margin = 12;
522 grid.attach (err, 0, 0, 1, 1);394 grid.attach (err, 0, 0, 1, 1);
523 grid.attach (new Widgets.LLabel.markup ("<b>"+395 grid.attach (err_label, 1, 0, 1, 1);
524 _("Audience needs %s to play this file.").printf (detail)+"</b>"), 1, 0, 1, 1);
525 grid.attach (phrase, 1, 1, 1, 2);396 grid.attach (phrase, 1, 1, 1, 2);
526397
527 dlg.add_button (_("Don't install"), 1);398 dlg.add_button (_("Don't install"), 1);
528 dlg.add_button (_("Install")+" "+detail, 0);399 dlg.add_button (_("Install")+" "+detail, 0);
529 400
530 (dlg.get_content_area () as Gtk.Container).add (grid);401 (dlg.get_content_area () as Gtk.Container).add (grid);
531
532 dlg.show_all ();402 dlg.show_all ();
533 if (dlg.run () == 0) {403 if (dlg.run () == 0) {
534 var installer = Gst.PbUtils.missing_plugin_message_get_installer_detail (msg);404 var installer = Gst.PbUtils.missing_plugin_message_get_installer_detail (msg);
535 var context = new Gst.PbUtils.InstallPluginsContext ();405 var context = new Gst.PbUtils.InstallPluginsContext ();
536 Gst.PbUtils.install_plugins_async ({installer}, context,406 Gst.PbUtils.install_plugins_async ({installer}, context, () => { //finished
537 () => { //finished407 debug ("Finished plugin install");
538 debug ("Finished plugin install\n");
539 Gst.update_registry ();408 Gst.update_registry ();
540 plugin_install_done ();409 plugin_install_done ();
541 playing = true;410 playing = true;
542 });411 });
543 }412 }
413
544 dlg.destroy ();414 dlg.destroy ();
545 }415 }
546 416
547 void set_timeout ()417 //TODO: Remove X Dependency!
548 {
549 if (hiding_timer != 0)
550 Source.remove (hiding_timer);
551
552 hiding_timer = GLib.Timeout.add (2000, () => {
553 unlock_hide ();
554 hiding_timer = 0;
555 return false;
556 });
557 }
558
559 void toggle_controls (bool show)
560 {
561 if (show) {
562 controls_hidden = false;
563 get_stage ().cursor_visible = true;
564 if (fullscreened)
565 panel.hidden = false;
566 } else {
567 get_stage ().cursor_visible = false;
568 controls_hidden = true;
569 panel.hidden = true;
570 }
571 }
572
573 //store the default values for setting back418 //store the default values for setting back
574 X.Display dpy; int timeout = -1; int interval; int prefer_blanking; int allow_exposures;419 X.Display dpy; int timeout = -1; int interval; int prefer_blanking; int allow_exposures;
575 void set_screensaver (bool enable)420 void set_screensaver (bool enable) {
576 {
577 if (dpy == null)421 if (dpy == null)
578 dpy = new X.Display ();422 dpy = new X.Display ();
579 423
580 if (timeout == -1)424 if (timeout == -1)
581 dpy.get_screensaver (out timeout, out interval, out prefer_blanking, out allow_exposures);425 dpy.get_screensaver (out timeout, out interval, out prefer_blanking, out allow_exposures);
426
582 dpy.set_screensaver (enable ? timeout : 0, interval, prefer_blanking, allow_exposures);427 dpy.set_screensaver (enable ? timeout : 0, interval, prefer_blanking, allow_exposures);
583 }428 }
584 429
585 //prevent screenlocking in Gnome 3 using org.gnome.SessionManager430 //prevent screenlocking in Gnome 3 using org.gnome.SessionManager
586 void set_screenlock (bool enable)431 void set_screenlock (bool enable) {
587 {432 try {
588 try{
589 session_manager = Bus.get_proxy_sync (BusType.SESSION, 433 session_manager = Bus.get_proxy_sync (BusType.SESSION,
590 "org.gnome.SessionManager", "/org/gnome/SessionManager");434 "org.gnome.SessionManager", "/org/gnome/SessionManager");
591 if (enable) {435 if (enable) {
592 session_manager.Uninhibit (inhibit_cookie);436 session_manager.Uninhibit (inhibit_cookie);
593 }else{437 } else {
594 inhibit_cookie = session_manager.Inhibit ("audience", 0, "Playing Video using Audience", 12);438 inhibit_cookie = session_manager.Inhibit ("audience", 0, "Playing Video using Audience", 12);
595 }439 }
596 } catch (Error e) { warning (e.message); }440 } catch (Error e) {
441 warning (e.message);
442 }
597 }443 }
598 }444 }
599}445}
600\ No newline at end of file446\ No newline at end of file

Subscribers

People subscribed via source and target branches