├── AUTHORS ├── po ├── POTFILES.skip ├── LINGUAS ├── POTFILES.in ├── ja.po ├── it.po ├── de.po ├── es.po ├── fr.po └── Makefile.in.in ├── data ├── dot.png ├── folder.png ├── background.png ├── iconshadow.png ├── foldermarker.png ├── sbmanager.desktop.in.in └── Makefile.am ├── Makefile.am ├── autogen.sh ├── .gitignore ├── README ├── src ├── Makefile.am ├── utility.h ├── iconstate.h ├── sbmgr.h ├── gui.h ├── sbitem.h ├── utility.c ├── device.h ├── iconstate.c ├── sbitem.c ├── sbmgr.c ├── main.c ├── device.c └── gui.c ├── m4 └── as-compiler-flag.m4 ├── configure.ac └── COPYING /AUTHORS: -------------------------------------------------------------------------------- 1 | Nikias Bassen 2 | Martin Szulecki 3 | -------------------------------------------------------------------------------- /po/POTFILES.skip: -------------------------------------------------------------------------------- 1 | data/sbmanager.desktop.in 2 | -------------------------------------------------------------------------------- /data/dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libimobiledevice/sbmanager/HEAD/data/dot.png -------------------------------------------------------------------------------- /data/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libimobiledevice/sbmanager/HEAD/data/folder.png -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | AUTOMAKE_OPTIONS = foreign 2 | ACLOCAL_AMFLAGS = -I m4 3 | SUBDIRS = data src po 4 | 5 | -------------------------------------------------------------------------------- /data/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libimobiledevice/sbmanager/HEAD/data/background.png -------------------------------------------------------------------------------- /data/iconshadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libimobiledevice/sbmanager/HEAD/data/iconshadow.png -------------------------------------------------------------------------------- /data/foldermarker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libimobiledevice/sbmanager/HEAD/data/foldermarker.png -------------------------------------------------------------------------------- /po/LINGUAS: -------------------------------------------------------------------------------- 1 | # List of source files containing translatable strings. 2 | # Please keep this list in alphabetic order. 3 | de 4 | es 5 | fr 6 | it 7 | ja 8 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | aclocal -I m4 3 | libtoolize 4 | autoheader 5 | automake --add-missing 6 | autoconf 7 | 8 | if [ -z "$NOCONFIGURE" ]; then 9 | ./configure "$@" 10 | fi 11 | -------------------------------------------------------------------------------- /data/sbmanager.desktop.in.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Terminal=false 4 | _Name=SpringBoard Manager 5 | _Comment=Manage SpringBoard icons on iPhone/iPod Touch devices 6 | Icon=sbmanager 7 | Exec=sbmanager 8 | Categories=GNOME;GTK;Utility; 9 | -------------------------------------------------------------------------------- /po/POTFILES.in: -------------------------------------------------------------------------------- 1 | # List of source files containing translatable strings. 2 | # Please keep this list in alphabetic order. 3 | data/sbmanager.desktop.in.in 4 | src/device.c 5 | src/gui.c 6 | src/iconstate.c 7 | src/main.c 8 | src/sbitem.c 9 | src/sbmgr.c 10 | src/utility.c 11 | -------------------------------------------------------------------------------- /data/Makefile.am: -------------------------------------------------------------------------------- 1 | pixmapdir = $(pkgdatadir) 2 | 3 | PIX = background.png dot.png folder.png foldermarker.png 4 | 5 | pixmap_DATA = $(PIX) 6 | 7 | desktopdir = $(datadir)/applications 8 | desktop_in_files = sbmanager.desktop.in 9 | desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) 10 | @INTLTOOL_DESKTOP_RULE@ 11 | 12 | EXTRA_DIST = \ 13 | $(pixmap_DATA) \ 14 | $(desktop_in_files) 15 | 16 | CLEANFILES = \ 17 | $(desktop_in_files) 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # git-ls-files --others --exclude-from=.git/info/exclude 2 | # Lines that start with '#' are comments. 3 | # For a project mostly in C, the following would be a good set of 4 | # exclude patterns (uncomment them if you want to use them): 5 | *.[oa] 6 | *~ 7 | *.po 8 | *.lo 9 | *.la 10 | autom4te.cache/* 11 | *.in 12 | */.deps/* 13 | m4/* 14 | *.swp 15 | aclocal.m4 16 | config.h 17 | config.log 18 | config.sub 19 | config.guess 20 | config.status 21 | configure 22 | depcomp 23 | install-sh 24 | compile 25 | main 26 | ltmain.sh 27 | missing 28 | mkinstalldirs 29 | libtool 30 | *Makefile 31 | stamp-h1 32 | src/.libs 33 | src/sbmanager 34 | data/data.h 35 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | SBManager 2 | ---------- 3 | 4 | SBManager is a program which allows to manage the SpringBoard icons on any 5 | iPhone/iPod Touch device running firmware 3.1 or later. 6 | 7 | This project has the following features: 8 | 9 | * Show SpringBoard icons as they appear on the device display. 10 | * Manage icons using drag and drop and upload changes back to the device. 11 | * Smooth hardware accelerated animations using the Clutter library. 12 | * Show the device's battery level and current clock. 13 | * Supports "five icon dock" extension. 14 | 15 | Source Code Repository: 16 | http://cgit.sukimashita.com/sbmanager.git/ 17 | 18 | For more information: 19 | http://matt.colyer.name/projects/iphone-linux/ 20 | 21 | README updated on: 22 | 2010-01-05 23 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CFLAGS = \ 2 | $(GLOBAL_CFLAGS) \ 3 | $(libimobiledevice_CFLAGS) \ 4 | $(libglib2_CFLAGS) \ 5 | $(libgthread2_CFLAGS) \ 6 | $(libplist_CFLAGS) \ 7 | $(libclutter_CFLAGS) \ 8 | $(libcluttergtk_CFLAGS) \ 9 | $(libgtk_CFLAGS) \ 10 | $(libgdkpixbuf_CFLAGS) \ 11 | -DSBMGR_DATA=\"$(pkgdatadir)\" 12 | 13 | AM_LDFLAGS = \ 14 | $(libimobiledevice_LIBS) \ 15 | $(libglib2_LIBS) \ 16 | $(libgthread2_LIBS) \ 17 | $(libplist_LIBS) \ 18 | $(libclutter_LIBS) \ 19 | $(libcluttergtk_LIBS) \ 20 | $(libgtk_LIBS) \ 21 | $(libgdkpixbuf_LIBS) 22 | 23 | bin_PROGRAMS = sbmanager 24 | 25 | noinst_LTLIBRARIES = libsbmanager.la 26 | libsbmanager_la_SOURCES = device.c device.h \ 27 | utility.c utility.h \ 28 | gui.c gui.h \ 29 | sbitem.c sbitem.h \ 30 | sbmgr.c sbmgr.h 31 | libsbmanager_la_CFLAGS = $(AM_CFLAGS) 32 | libsbmanager_la_LIBADD = $(AM_LDFLAGS) 33 | 34 | sbmanager_SOURCES = main.c 35 | sbmanager_CFLAGS = $(AM_CFLAGS) 36 | sbmanager_LDFLAGS = $(AM_LDFLAGS) 37 | sbmanager_LDADD = libsbmanager.la 38 | -------------------------------------------------------------------------------- /src/utility.h: -------------------------------------------------------------------------------- 1 | /** 2 | * utility.h 3 | * Debugging and helper function definitions. 4 | * 5 | * Copyright (C) 2009-2010 Nikias Bassen 6 | * Copyright (C) 2009-2010 Martin Szulecki 7 | * 8 | * Licensed under the GNU General Public License Version 2 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more profile. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 23 | * USA 24 | */ 25 | 26 | #ifndef UTILITY_H 27 | #define UTILITY_H 28 | #include 29 | 30 | /* debug */ 31 | void set_debug(gboolean debug); 32 | void debug_printf(const char *format, ...); 33 | 34 | /* helper */ 35 | gboolean elapsed_ms(struct timeval *tv, guint ms); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/iconstate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * iconstate.h 3 | * Serialization of iconstate from/to GList's (header file) 4 | * 5 | * Copyright (C) 2009-2010 Nikias Bassen 6 | * Copyright (C) 2009-2010 Martin Szulecki 7 | * 8 | * Licensed under the GNU General Public License Version 2 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more profile. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 23 | * USA 24 | */ 25 | 26 | #ifndef ICONSTATE_H 27 | #define ICONSTATE_H 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "iconstate.h" 36 | 37 | GList * iconstate_to_g_list(plist_t iconstate, GError **error); 38 | plist_t g_list_to_iconstate(GList *iconstate, GError **error); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/sbmgr.h: -------------------------------------------------------------------------------- 1 | /** 2 | * sbmgr.h 3 | * SBManager Widget definitions. 4 | * 5 | * Copyright (C) 2009-2010 Nikias Bassen 6 | * Copyright (C) 2009-2010 Martin Szulecki 7 | * 8 | * Licensed under the GNU General Public License Version 2 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more profile. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 23 | * USA 24 | */ 25 | 26 | #ifndef SBMGR_H 27 | #define SBMGR_H 28 | 29 | #include 30 | 31 | typedef void (*device_info_cb_t)(const char *device_name, const char *device_type); 32 | typedef void (*finished_cb_t)(gboolean success); 33 | 34 | GtkWidget *sbmgr_new(); 35 | void sbmgr_load(const char *uuid, device_info_cb_t info_callback, finished_cb_t finished_callback); 36 | void sbmgr_save(const char *uuid); 37 | void sbmgr_cleanup(); 38 | void sbmgr_finalize(); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/gui.h: -------------------------------------------------------------------------------- 1 | /** 2 | * gui.h 3 | * GUI definitions. 4 | * 5 | * Copyright (C) 2009-2010 Nikias Bassen 6 | * Copyright (C) 2009-2010 Martin Szulecki 7 | * 8 | * Licensed under the GNU General Public License Version 2 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more profile. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 23 | * USA 24 | */ 25 | 26 | #ifndef GUI_H 27 | #define GUI_H 28 | 29 | #include 30 | #include 31 | #include "sbmgr.h" 32 | 33 | typedef struct { 34 | char *uuid; 35 | device_info_t device_info; 36 | } SBManagerData; 37 | 38 | GtkWidget *gui_init(); 39 | void gui_deinit(); 40 | void gui_pages_load(const char *uuid, device_info_cb_t info_callback, finished_cb_t finshed_callback); 41 | void gui_pages_free(); 42 | 43 | plist_t gui_get_iconstate(const char *format_version); 44 | 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /m4/as-compiler-flag.m4: -------------------------------------------------------------------------------- 1 | dnl as-compiler-flag.m4 0.1.0 2 | 3 | dnl autostars m4 macro for detection of compiler flags 4 | 5 | dnl David Schleef 6 | 7 | dnl $Id: as-compiler-flag.m4,v 1.1 2005/12/15 23:35:19 ds Exp $ 8 | 9 | dnl AS_COMPILER_FLAG(CFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) 10 | dnl Tries to compile with the given CFLAGS. 11 | dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, 12 | dnl and ACTION-IF-NOT-ACCEPTED otherwise. 13 | 14 | AC_DEFUN([AS_COMPILER_FLAG], 15 | [ 16 | AC_MSG_CHECKING([to see if compiler understands $1]) 17 | 18 | save_CFLAGS="$CFLAGS" 19 | CFLAGS="$CFLAGS $1" 20 | 21 | AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) 22 | CFLAGS="$save_CFLAGS" 23 | 24 | if test "X$flag_ok" = Xyes ; then 25 | m4_ifvaln([$2],[$2]) 26 | true 27 | else 28 | m4_ifvaln([$3],[$3]) 29 | true 30 | fi 31 | AC_MSG_RESULT([$flag_ok]) 32 | ]) 33 | 34 | dnl AS_COMPILER_FLAGS(VAR, FLAGS) 35 | dnl Tries to compile with the given CFLAGS. 36 | 37 | AC_DEFUN([AS_COMPILER_FLAGS], 38 | [ 39 | list=$2 40 | flags_supported="" 41 | flags_unsupported="" 42 | AC_MSG_CHECKING([for supported compiler flags]) 43 | for each in $list 44 | do 45 | save_CFLAGS="$CFLAGS" 46 | CFLAGS="$CFLAGS $each" 47 | AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) 48 | CFLAGS="$save_CFLAGS" 49 | 50 | if test "X$flag_ok" = Xyes ; then 51 | flags_supported="$flags_supported $each" 52 | else 53 | flags_unsupported="$flags_unsupported $each" 54 | fi 55 | done 56 | AC_MSG_RESULT([$flags_supported]) 57 | if test "X$flags_unsupported" != X ; then 58 | AC_MSG_WARN([unsupported compiler flags: $flags_unsupported]) 59 | fi 60 | $1="$$1 $flags_supported" 61 | ]) 62 | 63 | -------------------------------------------------------------------------------- /src/sbitem.h: -------------------------------------------------------------------------------- 1 | /** 2 | * sbitem.h 3 | * SpringBoard Item representation 4 | * 5 | * Copyright (C) 2009-2010 Nikias Bassen 6 | * Copyright (C) 2009-2010 Martin Szulecki 7 | * 8 | * Licensed under the GNU General Public License Version 2 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more profile. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 23 | * USA 24 | */ 25 | 26 | #ifndef SBITEM_H 27 | #define SBITEM_H 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | typedef struct { 34 | plist_t node; 35 | ClutterActor *texture; 36 | ClutterActor *texture_shadow; 37 | ClutterActor *label; 38 | ClutterActor *label_shadow; 39 | gboolean drawn; 40 | gboolean is_dock_item; 41 | gboolean is_folder; 42 | gboolean enabled; 43 | GList *subitems; 44 | } SBItem; 45 | 46 | char *sbitem_get_display_name(SBItem *item); 47 | char *sbitem_get_display_identifier(SBItem *item); 48 | char *sbitem_get_icon_filename(SBItem *item); 49 | 50 | SBItem *sbitem_new(plist_t icon_info); 51 | SBItem *sbitem_new_with_subitems(plist_t icon_info, GList *subitems); 52 | void sbitem_free(SBItem *item); 53 | 54 | void g_func_sbitem_free(SBItem *item, gpointer data); 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/utility.c: -------------------------------------------------------------------------------- 1 | /** 2 | * utility.c 3 | * Debugging and helper function implementation. 4 | * 5 | * Copyright (C) 2009-2010 Nikias Bassen 6 | * Copyright (C) 2009-2010 Martin Szulecki 7 | * 8 | * Licensed under the GNU General Public License Version 2 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more profile. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 23 | * USA 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "utility.h" 33 | 34 | /* debug */ 35 | static gboolean debug_app = FALSE; 36 | 37 | void set_debug(gboolean debug) 38 | { 39 | debug_app = debug; 40 | } 41 | 42 | void debug_printf(const char *format, ...) 43 | { 44 | if (debug_app) { 45 | va_list args; 46 | va_start (args, format); 47 | vprintf(format, args); 48 | va_end (args); 49 | } 50 | } 51 | 52 | /* helper */ 53 | gboolean elapsed_ms(struct timeval *tv, guint ms) 54 | { 55 | struct timeval now; 56 | guint64 v1,v2; 57 | 58 | if (!tv) return FALSE; 59 | 60 | gettimeofday(&now, NULL); 61 | 62 | v1 = now.tv_sec*1000000 + now.tv_usec; 63 | v2 = tv->tv_sec*1000000 + tv->tv_usec; 64 | 65 | if (v1 < v2) { 66 | return TRUE; 67 | } 68 | 69 | if ((v1 - v2)/1000 > ms) { 70 | return TRUE; 71 | } else { 72 | return FALSE; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ(2.61) 5 | AC_INIT(sbmanager, 0.1.0, nospam@nowhere.com) 6 | AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip]) 7 | m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES]) 8 | AC_CONFIG_SRCDIR([src/]) 9 | AC_CONFIG_HEADERS([config.h]) 10 | AC_CONFIG_MACRO_DIR([m4]) 11 | 12 | # Checks for programs. 13 | AC_PROG_CC 14 | AM_PROG_CC_C_O 15 | AC_PROG_LIBTOOL 16 | 17 | # Checks for libraries. 18 | PKG_CHECK_MODULES(libimobiledevice, libimobiledevice-1.0 >= 0.9.7) 19 | PKG_CHECK_MODULES(libimobiledevice10, libimobiledevice-1.0 >= 1.0.0, libimobiledevice_1_0=yes, libimobiledevice_1_0=no) 20 | if test x"$libimobiledevice_1_0" = xyes; then 21 | AC_DEFINE([HAVE_LIBIMOBILEDEVICE_1_0], 1, [Define if libimobiledevice is using 1.0.0 API]) 22 | fi 23 | PKG_CHECK_MODULES(libimobiledevice11, libimobiledevice-1.0 >= 1.1.0, libimobiledevice_1_1=yes, libimobiledevice_1_1=no) 24 | if test x"$libimobiledevice_1_1" = xyes; then 25 | AC_DEFINE([HAVE_LIBIMOBILEDEVICE_1_1], 1, [Define if libimobiledevice is using 1.1.0 API]) 26 | fi 27 | PKG_CHECK_MODULES(libglib2, glib-2.0 >= 2.14.1) 28 | PKG_CHECK_MODULES(libgthread2, gthread-2.0 >= 2.14.1) 29 | PKG_CHECK_MODULES(libplist, libplist >= 1.0) 30 | PKG_CHECK_MODULES(libclutter, clutter-1.0 >= 1.0.6) 31 | PKG_CHECK_MODULES(libgtk, gtk+-2.0 >= 2.16) 32 | PKG_CHECK_MODULES(libcluttergtk, clutter-gtk-1.0 >= 1.0) 33 | PKG_CHECK_MODULES(libgdkpixbuf, gdk-pixbuf-2.0 >= 2.16) 34 | PKG_CHECK_MODULES(libbz2, bzip2 >= 1.0) 35 | 36 | # Checks for header files. 37 | AC_HEADER_STDC 38 | AC_CHECK_HEADERS([stdint.h stdlib.h string.h]) 39 | 40 | # Checks for typedefs, structures, and compiler characteristics. 41 | AC_C_CONST 42 | AC_TYPE_SIZE_T 43 | AC_TYPE_SSIZE_T 44 | AC_TYPE_UINT16_T 45 | AC_TYPE_UINT32_T 46 | AC_TYPE_UINT8_T 47 | 48 | # Checks for library functions. 49 | AC_FUNC_MALLOC 50 | AC_FUNC_REALLOC 51 | AC_CHECK_FUNCS([strcasecmp strdup strerror strndup]) 52 | 53 | AS_COMPILER_FLAGS(GLOBAL_CFLAGS, "-Wall -Wextra -Wmissing-declarations -Wredundant-decls -Wshadow -Wpointer-arith -Wwrite-strings -Wswitch-default -Wno-unused-parameter -Werror") 54 | AC_SUBST(GLOBAL_CFLAGS) 55 | 56 | # i18n 57 | 58 | GETTEXT_PACKAGE=sbmanager 59 | AC_SUBST([GETTEXT_PACKAGE]) 60 | AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], "$GETTEXT_PACKAGE", [Gettext package]) 61 | AM_GLIB_GNU_GETTEXT 62 | IT_PROG_INTLTOOL([0.35.0]) 63 | 64 | m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) 65 | 66 | AC_OUTPUT([ 67 | Makefile 68 | data/Makefile 69 | data/sbmanager.desktop.in 70 | src/Makefile 71 | po/Makefile.in 72 | ]) 73 | 74 | -------------------------------------------------------------------------------- /src/device.h: -------------------------------------------------------------------------------- 1 | /** 2 | * device.h 3 | * Device communication functions (header file) 4 | * 5 | * Copyright (C) 2009-2010 Nikias Bassen 6 | * Copyright (C) 2009-2010 Martin Szulecki 7 | * 8 | * Licensed under the GNU General Public License Version 2 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more profile. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 23 | * USA 24 | */ 25 | #ifndef DEVICE_H 26 | #define DEVICE_H 27 | #include 28 | #include 29 | 30 | struct device_info_int { 31 | char *uuid; 32 | char *device_name; 33 | char *device_type; 34 | guint battery_capacity; 35 | guint battery_poll_interval; 36 | /* layout on iOS 3.2+ */ 37 | guint home_screen_icon_columns; 38 | guint home_screen_icon_dock_max_count; 39 | guint home_screen_icon_height; 40 | guint home_screen_icon_rows; 41 | guint home_screen_icon_width; 42 | /* folders on iOS 4+ */ 43 | guint icon_folder_columns; 44 | guint icon_folder_max_pages; 45 | guint icon_folder_rows; 46 | gboolean icon_state_saves; 47 | }; 48 | typedef struct device_info_int *device_info_t; 49 | 50 | void device_init(); 51 | sbservices_client_t device_sbs_new(const char *uuid, uint32_t *osversion, GError **error); 52 | void device_sbs_free(sbservices_client_t sbc); 53 | gboolean device_sbs_get_iconstate(sbservices_client_t sbc, plist_t *iconstate, const char *format_version, GError **error); 54 | gboolean device_sbs_save_icon(sbservices_client_t sbc, char *display_identifier, char *filename, GError **error); 55 | gboolean device_sbs_set_iconstate(sbservices_client_t sbc, plist_t iconstate, GError **error); 56 | char *device_sbs_save_wallpaper(sbservices_client_t sbc, const char *uuid, GError **error); 57 | 58 | device_info_t device_info_new(); 59 | void device_info_free(device_info_t device_info); 60 | gboolean device_poll_battery_capacity(const char *uuid, device_info_t *device_info, GError **error); 61 | gboolean device_get_info(const char *uuid, device_info_t *device_info, GError **error); 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /po/ja.po: -------------------------------------------------------------------------------- 1 | # Japanese translation for sbmanager. 2 | # Copyright (C) 2010 Koichi Akabe 3 | # This file is distributed under the same license as the sbmanager package. 4 | # Koichi Akabe , 2010. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: sbmanager 1.0\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2010-05-24 11:53+0100\n" 11 | "PO-Revision-Date: 2010-06-05 21:31+0900\n" 12 | "Last-Translator: Koichi Akabe \n" 13 | "Language-Team: \n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | 18 | #: ../data/sbmanager.desktop.in.in.h:1 19 | msgid "Manage SpringBoard icons on iPhone/iPod Touch devices" 20 | msgstr "iPhone/iPod Touch の SpringBoard アイコンを管理します" 21 | 22 | #: ../data/sbmanager.desktop.in.in.h:2 23 | msgid "SpringBoard Manager" 24 | msgstr "SpringBoard マネージャ" 25 | 26 | #: ../src/device.c:62 ../src/device.c:223 27 | #, c-format 28 | msgid "No device found, is it plugged in?" 29 | msgstr "デバイスが見つかりませんでした。接続されていますか?" 30 | 31 | #: ../src/device.c:69 ../src/device.c:228 32 | #, c-format 33 | msgid "Could not connect to lockdownd!" 34 | msgstr "ロックダウンのための接続ができませんでした!" 35 | 36 | #: ../src/device.c:75 37 | #, c-format 38 | msgid "" 39 | "Could not start com.apple.springboardservices service! Remind that this " 40 | "feature is only supported in OS 3.1 and later!" 41 | msgstr "" 42 | "com.apple.springboardservices サービスを開始できませんでした! この機能は OS " 43 | "3.1 以降のみサポートされています。" 44 | 45 | #: ../src/device.c:80 46 | #, c-format 47 | msgid "Could not connect to springboardservices!" 48 | msgstr "springboardservices に接続できませんでした!" 49 | 50 | #: ../src/device.c:110 51 | #, c-format 52 | msgid "Could not get icon state!" 53 | msgstr "アイコンの状態を取得できませんでした!" 54 | 55 | #: ../src/device.c:115 56 | #, c-format 57 | msgid "icon state is not an array as expected!" 58 | msgstr "アイコン状態が期待通りの配列ではありません!" 59 | 60 | #: ../src/device.c:143 61 | #, c-format 62 | msgid "Could not get icon png data for '%s'" 63 | msgstr "'%s' のアイコンPNGデータを取得できませんでした " 64 | 65 | #: ../src/device.c:160 66 | #, c-format 67 | msgid "Could not set new icon state!" 68 | msgstr "新しいアイコン状態を設定できませんでした!" 69 | 70 | #: ../src/gui.c:1218 71 | #, c-format 72 | msgid "Unknown error occurred" 73 | msgstr "不明なエラーが発生しました" 74 | 75 | #: ../src/main.c:111 76 | msgid "Manage iPhone/iPod Touch SpringBoard from the computer" 77 | msgstr "コンピュータから iPhone/iPod Touch の SpringBoard を管理します" 78 | 79 | #: ../src/main.c:113 80 | msgid "Project Site" 81 | msgstr "プロジェクトサイト" 82 | 83 | #: ../src/main.c:145 84 | msgid "Error" 85 | msgstr "エラー" 86 | 87 | #: ../src/main.c:203 88 | msgid "Reload icons from device" 89 | msgstr "デバイスからアイコンを再読込します" 90 | 91 | #: ../src/main.c:207 92 | msgid "Upload changes to device" 93 | msgstr "変更をデバイスにアップロードします" 94 | 95 | #: ../src/main.c:211 96 | msgid "Get info about this cool program" 97 | msgstr "このクールなプログラムの情報を表示します" 98 | 99 | #: ../src/main.c:219 100 | msgid "Quit this program" 101 | msgstr "プログラムを終了します" 102 | 103 | #~ msgid "Manage _SpringBoard" 104 | #~ msgstr "Organizar el _SpringBoard" 105 | 106 | #~ msgid "Launch SBManager to manage the SpringBoard of this device" 107 | #~ msgstr "Ejecuta SBManager para organizar el Springboard de este dispositivo" 108 | -------------------------------------------------------------------------------- /po/it.po: -------------------------------------------------------------------------------- 1 | # Italian translation for sbmanager. 2 | # Copyright (C) 2010 Mario Polino 3 | # This file is distributed under the same license as the sbmanager package. 4 | # Mario Polino , 2010. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: sbmanager 1.0\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2010-07-21 19:10+0200\n" 11 | "PO-Revision-Date: \n" 12 | "Last-Translator: Mario Polino \n" 13 | "Language-Team: \n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | 18 | #: ../data/sbmanager.desktop.in.in.h:1 19 | msgid "Manage SpringBoard icons on iPhone/iPod Touch devices" 20 | msgstr "Organizza le icone della Springboard dell' iPhone/iPod Touch" 21 | 22 | #: ../data/sbmanager.desktop.in.in.h:2 23 | msgid "SpringBoard Manager" 24 | msgstr "" 25 | 26 | #: ../src/device.c:62 ../src/device.c:223 27 | #, c-format 28 | msgid "No device found, is it plugged in?" 29 | msgstr "Dispositivo non trovato! E' connesso?" 30 | 31 | #: ../src/device.c:69 ../src/device.c:228 32 | #, c-format 33 | msgid "Could not connect to lockdownd!" 34 | msgstr "Impossibile connettersi al lockdownd!" 35 | 36 | #: ../src/device.c:75 37 | #, c-format 38 | msgid "" 39 | "Could not start com.apple.springboardservices service! Remind that this " 40 | "feature is only supported in OS 3.1 and later!" 41 | msgstr "" 42 | "Impossibile connettersi a com.apple.springboardservices !" 43 | "Questa funzionalità è supportata solo dalla versione 3.1 in poi!" 44 | 45 | #: ../src/device.c:80 46 | #, c-format 47 | msgid "Could not connect to springboardservices!" 48 | msgstr "Impossibile connettersi a springboardservices!" 49 | 50 | #: ../src/device.c:110 51 | #, c-format 52 | msgid "Could not get icon state!" 53 | msgstr "Impossibile ottenere lo stato delle icone!" 54 | 55 | #: ../src/device.c:115 56 | #, c-format 57 | msgid "icon state is not an array as expected!" 58 | msgstr "lo stato delle icone non è un array!" 59 | 60 | #: ../src/device.c:143 61 | #, c-format 62 | msgid "Could not get icon png data for '%s'" 63 | msgstr "Impossibile ottenere l'icona png per '%s'!" 64 | 65 | #: ../src/device.c:160 66 | #, c-format 67 | msgid "Could not set new icon state!" 68 | msgstr "Impossibile impostare il nuovo stato delle icone!" 69 | 70 | #: ../src/gui.c:1218 71 | #, c-format 72 | msgid "Unknown error occurred" 73 | msgstr "Errore sconosciuto" 74 | 75 | #: ../src/main.c:111 76 | msgid "Manage iPhone/iPod Touch SpringBoard from the computer" 77 | msgstr "Gestisci la SpringBoard del iPhone/iPod Touch dal computer" 78 | 79 | #: ../src/main.c:113 80 | msgid "Project Site" 81 | msgstr "Sito del Progetto" 82 | 83 | #: ../src/main.c:145 84 | msgid "Error" 85 | msgstr "Errore" 86 | 87 | #: ../src/main.c:203 88 | msgid "Reload icons from device" 89 | msgstr "Ricarico le icone dal dispositivo" 90 | 91 | #: ../src/main.c:207 92 | msgid "Upload changes to device" 93 | msgstr "Invio dei cambiamenti al dispositivo" 94 | 95 | #: ../src/main.c:211 96 | msgid "Get info about this cool program" 97 | msgstr "Ottieni informazione su questo programma" 98 | 99 | #: ../src/main.c:219 100 | msgid "Quit this program" 101 | msgstr "Chiudi questo programma" 102 | 103 | #~ msgid "Manage _SpringBoard" 104 | #~ msgstr "Gestisci la _SpringBoard" 105 | 106 | #~ msgid "Launch SBManager to manage the SpringBoard of this device" 107 | #~ msgstr "Lancia SBManager per gestire la SpringBoard del dispositivo" 108 | -------------------------------------------------------------------------------- /po/de.po: -------------------------------------------------------------------------------- 1 | # German translation for sbmanager. 2 | # Copyright (C) 2010 Nikias Bassen 3 | # This file is distributed under the same license as the sbmanager package. 4 | # Nikias Bassen , 2010. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: sbmanager 1.0\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2010-04-11 16:35+0200\n" 11 | "PO-Revision-Date: 2010-01-18 04:30+0100\n" 12 | "Last-Translator: Nikias Bassen \n" 13 | "Language-Team: \n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | 18 | #: ../data/sbmanager.desktop.in.in.h:1 19 | msgid "Manage SpringBoard icons on iPhone/iPod Touch devices" 20 | msgstr "" 21 | 22 | #: ../data/sbmanager.desktop.in.in.h:2 23 | msgid "SpringBoard Manager" 24 | msgstr "" 25 | 26 | #: ../src/device.c:62 ../src/device.c:223 27 | #, c-format 28 | msgid "No device found, is it plugged in?" 29 | msgstr "Kein Gerät gefunden, habe Sie eines angeschlossen?" 30 | 31 | #: ../src/device.c:69 ../src/device.c:228 32 | #, c-format 33 | msgid "Could not connect to lockdownd!" 34 | msgstr "Kann mich nicht mit lockdownd verbinden!" 35 | 36 | #: ../src/device.c:75 37 | #, c-format 38 | msgid "" 39 | "Could not start com.apple.springboardservices service! Remind that this " 40 | "feature is only supported in OS 3.1 and later!" 41 | msgstr "" 42 | "Konnte com.apple.springboardservices nicht starten! Bedenken Sie,dass diese " 43 | "Funktionalität erst seit OS 3.1 verfügbar ist!" 44 | 45 | #: ../src/device.c:80 46 | #, c-format 47 | msgid "Could not connect to springboardservices!" 48 | msgstr "Verbindung zu springboardservices auf dem Gerät nicht möglich!" 49 | 50 | #: ../src/device.c:110 51 | #, c-format 52 | msgid "Could not get icon state!" 53 | msgstr "Konnte icon state nicht laden!" 54 | 55 | #: ../src/device.c:115 56 | #, c-format 57 | msgid "icon state is not an array as expected!" 58 | msgstr "icon state ist unerwarteterweise kein Array!" 59 | 60 | #: ../src/device.c:143 61 | #, c-format 62 | msgid "Could not get icon png data for '%s'" 63 | msgstr "Konnte icon png-Daten für '%s' nicht laden!" 64 | 65 | #: ../src/device.c:160 66 | #, c-format 67 | msgid "Could not set new icon state!" 68 | msgstr "Konnte neuen icon state nicht setzen!" 69 | 70 | #: ../src/gui.c:1218 71 | #, c-format 72 | msgid "Unknown error occurred" 73 | msgstr "Ein unbekannter Fehler ist aufgetreten" 74 | 75 | #: ../src/main.c:111 76 | msgid "Manage iPhone/iPod Touch SpringBoard from the computer" 77 | msgstr "iPhone/iPod Touch SpringBoard vom Computer aus bearbeiten" 78 | 79 | #: ../src/main.c:113 80 | msgid "Project Site" 81 | msgstr "Projektseite" 82 | 83 | #: ../src/main.c:145 84 | msgid "Error" 85 | msgstr "Fehler" 86 | 87 | #: ../src/main.c:203 88 | msgid "Reload icons from device" 89 | msgstr "Symbole erneut vom Gerät laden" 90 | 91 | #: ../src/main.c:207 92 | msgid "Upload changes to device" 93 | msgstr "Änderungen auf das Gerät übertragen" 94 | 95 | #: ../src/main.c:211 96 | msgid "Get info about this cool program" 97 | msgstr "Informationen über dieses krasse Programm" 98 | 99 | #: ../src/main.c:219 100 | msgid "Quit this program" 101 | msgstr "Programm beenden" 102 | 103 | #~ msgid "Manage _SpringBoard" 104 | #~ msgstr "_SpringBoard bearbeiten" 105 | 106 | #~ msgid "Launch SBManager to manage the SpringBoard of this device" 107 | #~ msgstr "" 108 | #~ "Startet SBManager mit dem Sie das SpringBoard dieses Gerätes bearbeiten " 109 | #~ "können" 110 | -------------------------------------------------------------------------------- /po/es.po: -------------------------------------------------------------------------------- 1 | # Spanish translation for sbmanager. 2 | # Copyright (C) 2010 Itxaka Serrano 3 | # This file is distributed under the same license as the sbmanager package. 4 | # Itxaka Serrano , 2010. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: sbmanager 1.0\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2010-05-24 11:53+0100\n" 11 | "PO-Revision-Date: \n" 12 | "Last-Translator: Itxaka Serrano \n" 13 | "Language-Team: \n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | 18 | #: ../data/sbmanager.desktop.in.in.h:1 19 | msgid "Manage SpringBoard icons on iPhone/iPod Touch devices" 20 | msgstr "Ejecuta SBManager para organizar el Springboard de este dispositivo" 21 | 22 | #: ../data/sbmanager.desktop.in.in.h:2 23 | msgid "SpringBoard Manager" 24 | msgstr "" 25 | 26 | #: ../src/device.c:62 ../src/device.c:223 27 | #, c-format 28 | msgid "No device found, is it plugged in?" 29 | msgstr "Ningun dispositivo encontrado, ¿Esta conectado?" 30 | 31 | #: ../src/device.c:69 ../src/device.c:228 32 | #, c-format 33 | msgid "Could not connect to lockdownd!" 34 | msgstr "No se puede conectar con lockdownd!" 35 | 36 | #: ../src/device.c:75 37 | #, c-format 38 | msgid "" 39 | "Could not start com.apple.springboardservices service! Remind that this " 40 | "feature is only supported in OS 3.1 and later!" 41 | msgstr "" 42 | "No se puede arrancar el servicio com.apple.springboardservices!Esta " 43 | "caracteristica solo esta disponible con OS 3.1 y posteriores" 44 | 45 | #: ../src/device.c:80 46 | #, c-format 47 | msgid "Could not connect to springboardservices!" 48 | msgstr "¡No se puede conectar con springboardservices!" 49 | 50 | #: ../src/device.c:110 51 | #, c-format 52 | msgid "Could not get icon state!" 53 | msgstr "¡No es posible obtener el estado de los iconos!" 54 | 55 | #: ../src/device.c:115 56 | #, c-format 57 | msgid "icon state is not an array as expected!" 58 | msgstr "¡El estado del icono no es un array como se esperaba!" 59 | 60 | #: ../src/device.c:143 61 | #, c-format 62 | msgid "Could not get icon png data for '%s'" 63 | msgstr "¡No se puede obtener datos png del icono '%s'!" 64 | 65 | #: ../src/device.c:160 66 | #, c-format 67 | msgid "Could not set new icon state!" 68 | msgstr "¡No se puede establecer el nuevo estado de los iconos!" 69 | 70 | #: ../src/gui.c:1218 71 | #, c-format 72 | msgid "Unknown error occurred" 73 | msgstr "Error desconocido encontrado" 74 | 75 | #: ../src/main.c:111 76 | msgid "Manage iPhone/iPod Touch SpringBoard from the computer" 77 | msgstr "Maneja el Springboard de tu iPhone/iPod Touch desde tu ordenador" 78 | 79 | #: ../src/main.c:113 80 | msgid "Project Site" 81 | msgstr "Web del projecto" 82 | 83 | #: ../src/main.c:145 84 | msgid "Error" 85 | msgstr "Error" 86 | 87 | #: ../src/main.c:203 88 | msgid "Reload icons from device" 89 | msgstr "Recargar los iconos desde el dispositivo" 90 | 91 | #: ../src/main.c:207 92 | msgid "Upload changes to device" 93 | msgstr "Transferir los cambios al dispositivo" 94 | 95 | #: ../src/main.c:211 96 | msgid "Get info about this cool program" 97 | msgstr "Mas informacion sobre el programa" 98 | 99 | #: ../src/main.c:219 100 | msgid "Quit this program" 101 | msgstr "Salir del programa" 102 | 103 | #~ msgid "Manage _SpringBoard" 104 | #~ msgstr "Organizar el _SpringBoard" 105 | 106 | #~ msgid "Launch SBManager to manage the SpringBoard of this device" 107 | #~ msgstr "Ejecuta SBManager para organizar el Springboard de este dispositivo" 108 | -------------------------------------------------------------------------------- /po/fr.po: -------------------------------------------------------------------------------- 1 | # French translation for sbmanager. 2 | # Copyright (C) 2010 Christophe Fergeau 3 | # This file is distributed under the same license as the sbmanager package. 4 | # Christophe Fergeau , 2010. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: sbmanager 1.0\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2010-04-11 16:35+0200\n" 11 | "PO-Revision-Date: 2010-01-18 04:30+0100\n" 12 | "Last-Translator: Christophe Fergeau \n" 13 | "Language-Team: \n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | 18 | #: ../data/sbmanager.desktop.in.in.h:1 19 | msgid "Manage SpringBoard icons on iPhone/iPod Touch devices" 20 | msgstr "" 21 | 22 | #: ../data/sbmanager.desktop.in.in.h:2 23 | msgid "SpringBoard Manager" 24 | msgstr "" 25 | 26 | #: ../src/device.c:62 ../src/device.c:223 27 | #, c-format 28 | msgid "No device found, is it plugged in?" 29 | msgstr "Impossible de trouver le périphérique, est-il branché ?" 30 | 31 | #: ../src/device.c:69 ../src/device.c:228 32 | #, c-format 33 | msgid "Could not connect to lockdownd!" 34 | msgstr "Impossible de se connecter à lockdownd!" 35 | 36 | #: ../src/device.c:75 37 | #, c-format 38 | msgid "" 39 | "Could not start com.apple.springboardservices service! Remind that this " 40 | "feature is only supported in OS 3.1 and later!" 41 | msgstr "" 42 | "Impossible de démarrer le service com.apple.springboardservices !Cette " 43 | "fonctionnalité n'est supportée que par les versions 3.1 et ultérieures de " 44 | "l'OS !" 45 | 46 | #: ../src/device.c:80 47 | #, c-format 48 | msgid "Could not connect to springboardservices!" 49 | msgstr "Impossible de se connecter à springboardservices !" 50 | 51 | #: ../src/device.c:110 52 | #, c-format 53 | msgid "Could not get icon state!" 54 | msgstr "Impossible d'obtenir la disposition des icônes !" 55 | 56 | #: ../src/device.c:115 57 | #, c-format 58 | msgid "icon state is not an array as expected!" 59 | msgstr "l'état des icônes n'est pas un tableau comme attendu" 60 | 61 | #: ../src/device.c:143 62 | #, c-format 63 | msgid "Could not get icon png data for '%s'" 64 | msgstr "Impossible d'obtenir les données PNG de l'icône '%s'!" 65 | 66 | #: ../src/device.c:160 67 | #, c-format 68 | msgid "Could not set new icon state!" 69 | msgstr "Impossible de définir une nouvelle disposition pour les icônes !" 70 | 71 | #: ../src/gui.c:1218 72 | #, c-format 73 | msgid "Unknown error occurred" 74 | msgstr "Une erreur inconnue s'est produite" 75 | 76 | #: ../src/main.c:111 77 | msgid "Manage iPhone/iPod Touch SpringBoard from the computer" 78 | msgstr "Gérer le SpringBoard de l'iPhone/iPod Touch à partir d'un ordinateur" 79 | 80 | #: ../src/main.c:113 81 | msgid "Project Site" 82 | msgstr "Site du projet" 83 | 84 | #: ../src/main.c:145 85 | msgid "Error" 86 | msgstr "Erreur" 87 | 88 | #: ../src/main.c:203 89 | msgid "Reload icons from device" 90 | msgstr "Rélire les icônes à partir du périphérique" 91 | 92 | #: ../src/main.c:207 93 | msgid "Upload changes to device" 94 | msgstr "Transférer les modifications vers le périphérique" 95 | 96 | #: ../src/main.c:211 97 | msgid "Get info about this cool program" 98 | msgstr "À propos de cet incroyable programme" 99 | 100 | #: ../src/main.c:219 101 | msgid "Quit this program" 102 | msgstr "Quitter le programme" 103 | 104 | #~ msgid "Manage _SpringBoard" 105 | #~ msgstr "Gérer le _SpringBoard" 106 | 107 | #~ msgid "Launch SBManager to manage the SpringBoard of this device" 108 | #~ msgstr "Démarrer SBManager pour gérer le SpringBoard de cet appareil" 109 | -------------------------------------------------------------------------------- /src/iconstate.c: -------------------------------------------------------------------------------- 1 | /** 2 | * iconstate.c 3 | * Serialization of iconstate from/to GList's 4 | * 5 | * Copyright (C) 2009-2010 Nikias Bassen 6 | * Copyright (C) 2009-2010 Martin Szulecki 7 | * 8 | * Licensed under the GNU General Public License Version 2 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more profile. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 23 | * USA 24 | */ 25 | 26 | #ifdef HAVE_CONFIG_H 27 | #include 28 | #endif 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "iconstate.h" 37 | 38 | GList * iconstate_to_g_list(plist_t iconstate, GError **error) 39 | { 40 | 41 | } 42 | 43 | plist_t g_list_to_iconstate(GList *iconstate, GError **error) 44 | { 45 | plist_t iconstate = NULL; 46 | plist_t pdockarray = NULL; 47 | plist_t pdockitems = NULL; 48 | guint i; 49 | 50 | guint count = g_list_length(dockitems); 51 | pdockitems = plist_new_array(); 52 | for (i = 0; i < count; i++) { 53 | SBItem *item = g_list_nth_data(dockitems, i); 54 | if (!item) { 55 | continue; 56 | } 57 | plist_t valuenode = plist_dict_get_item(item->node, "displayIdentifier"); 58 | if (!valuenode) { 59 | printf("could not get displayIdentifier\n"); 60 | continue; 61 | } 62 | 63 | plist_t pitem = plist_new_dict(); 64 | plist_dict_insert_item(pitem, "displayIdentifier", plist_copy(valuenode)); 65 | plist_array_append_item(pdockitems, pitem); 66 | } 67 | for (i = count; i < num_dock_items; i++) { 68 | plist_array_append_item(pdockitems, plist_new_bool(0)); 69 | } 70 | pdockarray = plist_new_array(); 71 | plist_array_append_item(pdockarray, pdockitems); 72 | 73 | iconstate = plist_new_array(); 74 | plist_array_append_item(iconstate, pdockarray); 75 | 76 | for (i = 0; i < g_list_length(sbpages); i++) { 77 | GList *page = g_list_nth_data(sbpages, i); 78 | if (page) { 79 | guint j; 80 | count = g_list_length(page); 81 | if (count <= 0) { 82 | continue; 83 | } 84 | plist_t ppage = plist_new_array(); 85 | plist_t row = NULL; 86 | for (j = 0; j < 16; j++) { 87 | SBItem *item = g_list_nth_data(page, j); 88 | if ((j % 4) == 0) { 89 | row = plist_new_array(); 90 | plist_array_append_item(ppage, row); 91 | } 92 | if (item && item->node) { 93 | plist_t valuenode = plist_dict_get_item(item->node, 94 | "displayIdentifier"); 95 | if (!valuenode) { 96 | printf("could not get displayIdentifier\n"); 97 | continue; 98 | } 99 | 100 | plist_t pitem = plist_new_dict(); 101 | plist_dict_insert_item(pitem, "displayIdentifier", plist_copy(valuenode)); 102 | plist_array_append_item(row, pitem); 103 | } else { 104 | plist_array_append_item(row, plist_new_bool(0)); 105 | } 106 | } 107 | plist_array_append_item(iconstate, plist_copy(ppage)); 108 | plist_free(ppage); 109 | } 110 | } 111 | 112 | return iconstate; 113 | } 114 | -------------------------------------------------------------------------------- /src/sbitem.c: -------------------------------------------------------------------------------- 1 | /** 2 | * sbitem.c 3 | * SpringBoard Item representation 4 | * 5 | * Copyright (C) 2009-2010 Nikias Bassen 6 | * Copyright (C) 2009-2010 Martin Szulecki 7 | * 8 | * Licensed under the GNU General Public License Version 2 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more profile. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 23 | * USA 24 | */ 25 | 26 | #ifdef HAVE_CONFIG_H 27 | #include 28 | #endif 29 | 30 | #include 31 | 32 | #include "sbitem.h" 33 | 34 | char *sbitem_get_display_name(SBItem *item) 35 | { 36 | char *strval = NULL; 37 | plist_t node = plist_dict_get_item(item->node, "displayName"); 38 | if (node && plist_get_node_type(node) == PLIST_STRING) { 39 | plist_get_string_val(node, &strval); 40 | } 41 | return strval; 42 | } 43 | 44 | 45 | char *sbitem_get_display_identifier(SBItem *item) 46 | { 47 | char *strval = NULL; 48 | plist_t node = plist_dict_get_item(item->node, "displayIdentifier"); 49 | if (node && plist_get_node_type(node) == PLIST_STRING) { 50 | plist_get_string_val(node, &strval); 51 | } 52 | return strval; 53 | } 54 | 55 | SBItem *sbitem_new(plist_t icon_info) 56 | { 57 | SBItem *item = NULL; 58 | 59 | if (plist_get_node_type(icon_info) != PLIST_DICT) { 60 | return item; 61 | } 62 | 63 | item = g_new0(SBItem, 1); 64 | item->node = plist_copy(icon_info); 65 | item->texture = NULL; 66 | item->drawn = FALSE; 67 | item->is_dock_item = FALSE; 68 | item->is_folder = FALSE; 69 | item->enabled = TRUE; 70 | item->subitems = NULL; 71 | 72 | return item; 73 | } 74 | 75 | SBItem *sbitem_new_with_subitems(plist_t icon_info, GList *subitems) 76 | { 77 | SBItem *item = sbitem_new(icon_info); 78 | if (item) { 79 | item->subitems = subitems; 80 | item->is_folder = TRUE; 81 | } 82 | return item; 83 | } 84 | 85 | void sbitem_free(SBItem *item) 86 | { 87 | if (item) { 88 | if (item->node) { 89 | plist_free(item->node); 90 | } 91 | if (item->texture && CLUTTER_IS_ACTOR(item->texture)) { 92 | ClutterActor *parent = clutter_actor_get_parent(item->texture); 93 | if (parent) { 94 | clutter_actor_destroy(parent); 95 | item->texture = NULL; 96 | item->label = NULL; 97 | } else { 98 | clutter_actor_destroy(item->texture); 99 | item->texture = NULL; 100 | } 101 | } 102 | if (item->texture_shadow && CLUTTER_IS_ACTOR(item->texture_shadow)) { 103 | clutter_actor_destroy(item->texture_shadow); 104 | item->texture_shadow = NULL; 105 | } 106 | if (item->label_shadow && CLUTTER_IS_ACTOR(item->label_shadow)) { 107 | clutter_actor_destroy(item->label_shadow); 108 | item->label_shadow = NULL; 109 | } 110 | 111 | if (item->subitems) { 112 | g_list_foreach(item->subitems, (GFunc)(g_func_sbitem_free), NULL); 113 | g_list_free(item->subitems); 114 | } 115 | if (item->label && CLUTTER_IS_ACTOR(item->label)) { 116 | clutter_actor_destroy(item->label); 117 | item->label = NULL; 118 | } 119 | free(item); 120 | } 121 | } 122 | 123 | void g_func_sbitem_free(SBItem *item, gpointer data) 124 | { 125 | sbitem_free(item); 126 | } 127 | 128 | char *sbitem_get_icon_filename(SBItem *item) 129 | { 130 | static gboolean create_dir = FALSE; 131 | const char *value; 132 | char *filename, *path; 133 | 134 | if (create_dir == FALSE) { 135 | path = g_build_filename (g_get_user_cache_dir (), 136 | "libimobiledevice", 137 | "icons", NULL); 138 | if (g_mkdir_with_parents (path, 0755) >= 0) 139 | create_dir = TRUE; 140 | g_free (path); 141 | } 142 | 143 | value = sbitem_get_display_identifier(item); 144 | if (!value) 145 | return NULL; 146 | 147 | filename = g_strdup_printf ("%s.png", value); 148 | path = g_build_filename (g_get_user_cache_dir (), 149 | "libimobiledevice", 150 | "icons", 151 | filename, NULL); 152 | g_free (filename); 153 | return path; 154 | } 155 | -------------------------------------------------------------------------------- /po/Makefile.in.in: -------------------------------------------------------------------------------- 1 | # Makefile for program source directory in GNU NLS utilities package. 2 | # Copyright (C) 1995, 1996, 1997 by Ulrich Drepper 3 | # Copyright (C) 2004-2008 Rodney Dawes 4 | # 5 | # This file may be copied and used freely without restrictions. It may 6 | # be used in projects which are not available under a GNU Public License, 7 | # but which still want to provide support for the GNU gettext functionality. 8 | # 9 | # - Modified by Owen Taylor to use GETTEXT_PACKAGE 10 | # instead of PACKAGE and to look for po2tbl in ./ not in intl/ 11 | # 12 | # - Modified by jacob berkman to install 13 | # Makefile.in.in and po2tbl.sed.in for use with glib-gettextize 14 | # 15 | # - Modified by Rodney Dawes for use with intltool 16 | # 17 | # We have the following line for use by intltoolize: 18 | # INTLTOOL_MAKEFILE 19 | 20 | GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ 21 | PACKAGE = @PACKAGE@ 22 | VERSION = @VERSION@ 23 | 24 | SHELL = @SHELL@ 25 | 26 | srcdir = @srcdir@ 27 | top_srcdir = @top_srcdir@ 28 | top_builddir = @top_builddir@ 29 | VPATH = @srcdir@ 30 | 31 | prefix = @prefix@ 32 | exec_prefix = @exec_prefix@ 33 | datadir = @datadir@ 34 | datarootdir = @datarootdir@ 35 | libdir = @libdir@ 36 | DATADIRNAME = @DATADIRNAME@ 37 | itlocaledir = $(prefix)/$(DATADIRNAME)/locale 38 | subdir = po 39 | install_sh = @install_sh@ 40 | # Automake >= 1.8 provides @mkdir_p@. 41 | # Until it can be supposed, use the safe fallback: 42 | mkdir_p = $(install_sh) -d 43 | 44 | INSTALL = @INSTALL@ 45 | INSTALL_DATA = @INSTALL_DATA@ 46 | 47 | GMSGFMT = @GMSGFMT@ 48 | MSGFMT = @MSGFMT@ 49 | XGETTEXT = @XGETTEXT@ 50 | INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ 51 | INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ 52 | MSGMERGE = INTLTOOL_EXTRACT=$(INTLTOOL_EXTRACT) srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --dist 53 | GENPOT = INTLTOOL_EXTRACT=$(INTLTOOL_EXTRACT) srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --pot 54 | 55 | ALL_LINGUAS = @ALL_LINGUAS@ 56 | 57 | PO_LINGUAS=$(shell if test -r $(srcdir)/LINGUAS; then grep -v "^\#" $(srcdir)/LINGUAS; else echo "$(ALL_LINGUAS)"; fi) 58 | 59 | USER_LINGUAS=$(shell if test -n "$(LINGUAS)"; then LLINGUAS="$(LINGUAS)"; ALINGUAS="$(ALL_LINGUAS)"; for lang in $$LLINGUAS; do if test -n "`grep '^$$lang$$' $(srcdir)/LINGUAS 2>/dev/null`" -o -n "`echo $$ALINGUAS|tr ' ' '\n'|grep '^$$lang$$'`"; then printf "$$lang "; fi; done; fi) 60 | 61 | USE_LINGUAS=$(shell if test -n "$(USER_LINGUAS)" -o -n "$(LINGUAS)"; then LLINGUAS="$(USER_LINGUAS)"; else if test -n "$(PO_LINGUAS)"; then LLINGUAS="$(PO_LINGUAS)"; else LLINGUAS="$(ALL_LINGUAS)"; fi; fi; for lang in $$LLINGUAS; do printf "$$lang "; done) 62 | 63 | POFILES=$(shell LINGUAS="$(PO_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.po "; done) 64 | 65 | DISTFILES = Makefile.in.in POTFILES.in $(POFILES) 66 | EXTRA_DISTFILES = ChangeLog POTFILES.skip Makevars LINGUAS 67 | 68 | POTFILES = \ 69 | # This comment gets stripped out 70 | 71 | CATALOGS=$(shell LINGUAS="$(USE_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.gmo "; done) 72 | 73 | .SUFFIXES: 74 | .SUFFIXES: .po .pox .gmo .mo .msg .cat 75 | 76 | .po.pox: 77 | $(MAKE) $(GETTEXT_PACKAGE).pot 78 | $(MSGMERGE) $< $(GETTEXT_PACKAGE).pot -o $*.pox 79 | 80 | .po.mo: 81 | $(MSGFMT) -o $@ $< 82 | 83 | .po.gmo: 84 | file=`echo $* | sed 's,.*/,,'`.gmo \ 85 | && rm -f $$file && $(GMSGFMT) -o $$file $< 86 | 87 | .po.cat: 88 | sed -f ../intl/po2msg.sed < $< > $*.msg \ 89 | && rm -f $@ && gencat $@ $*.msg 90 | 91 | 92 | all: all-@USE_NLS@ 93 | 94 | all-yes: $(CATALOGS) 95 | all-no: 96 | 97 | $(GETTEXT_PACKAGE).pot: $(POTFILES) 98 | $(GENPOT) 99 | 100 | install: install-data 101 | install-data: install-data-@USE_NLS@ 102 | install-data-no: all 103 | install-data-yes: all 104 | linguas="$(USE_LINGUAS)"; \ 105 | for lang in $$linguas; do \ 106 | dir=$(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES; \ 107 | $(mkdir_p) $$dir; \ 108 | if test -r $$lang.gmo; then \ 109 | $(INSTALL_DATA) $$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ 110 | echo "installing $$lang.gmo as $$dir/$(GETTEXT_PACKAGE).mo"; \ 111 | else \ 112 | $(INSTALL_DATA) $(srcdir)/$$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ 113 | echo "installing $(srcdir)/$$lang.gmo as" \ 114 | "$$dir/$(GETTEXT_PACKAGE).mo"; \ 115 | fi; \ 116 | if test -r $$lang.gmo.m; then \ 117 | $(INSTALL_DATA) $$lang.gmo.m $$dir/$(GETTEXT_PACKAGE).mo.m; \ 118 | echo "installing $$lang.gmo.m as $$dir/$(GETTEXT_PACKAGE).mo.m"; \ 119 | else \ 120 | if test -r $(srcdir)/$$lang.gmo.m ; then \ 121 | $(INSTALL_DATA) $(srcdir)/$$lang.gmo.m \ 122 | $$dir/$(GETTEXT_PACKAGE).mo.m; \ 123 | echo "installing $(srcdir)/$$lang.gmo.m as" \ 124 | "$$dir/$(GETTEXT_PACKAGE).mo.m"; \ 125 | else \ 126 | true; \ 127 | fi; \ 128 | fi; \ 129 | done 130 | 131 | # Empty stubs to satisfy archaic automake needs 132 | dvi info tags TAGS ID: 133 | 134 | # Define this as empty until I found a useful application. 135 | install-exec installcheck: 136 | 137 | uninstall: 138 | linguas="$(USE_LINGUAS)"; \ 139 | for lang in $$linguas; do \ 140 | rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo; \ 141 | rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo.m; \ 142 | done 143 | 144 | check: all $(GETTEXT_PACKAGE).pot 145 | rm -f missing notexist 146 | srcdir=$(srcdir) $(INTLTOOL_UPDATE) -m 147 | if [ -r missing -o -r notexist ]; then \ 148 | exit 1; \ 149 | fi 150 | 151 | mostlyclean: 152 | rm -f *.pox $(GETTEXT_PACKAGE).pot *.old.po cat-id-tbl.tmp 153 | rm -f .intltool-merge-cache 154 | 155 | clean: mostlyclean 156 | 157 | distclean: clean 158 | rm -f Makefile Makefile.in POTFILES stamp-it 159 | rm -f *.mo *.msg *.cat *.cat.m *.gmo 160 | 161 | maintainer-clean: distclean 162 | @echo "This command is intended for maintainers to use;" 163 | @echo "it deletes files that may require special tools to rebuild." 164 | rm -f Makefile.in.in 165 | 166 | distdir = ../$(PACKAGE)-$(VERSION)/$(subdir) 167 | dist distdir: $(DISTFILES) 168 | dists="$(DISTFILES)"; \ 169 | extra_dists="$(EXTRA_DISTFILES)"; \ 170 | for file in $$extra_dists; do \ 171 | test -f $(srcdir)/$$file && dists="$$dists $(srcdir)/$$file"; \ 172 | done; \ 173 | for file in $$dists; do \ 174 | test -f $$file || file="$(srcdir)/$$file"; \ 175 | ln $$file $(distdir) 2> /dev/null \ 176 | || cp -p $$file $(distdir); \ 177 | done 178 | 179 | update-po: Makefile 180 | $(MAKE) $(GETTEXT_PACKAGE).pot 181 | tmpdir=`pwd`; \ 182 | linguas="$(USE_LINGUAS)"; \ 183 | for lang in $$linguas; do \ 184 | echo "$$lang:"; \ 185 | result="`$(MSGMERGE) -o $$tmpdir/$$lang.new.po $$lang`"; \ 186 | if $$result; then \ 187 | if cmp $(srcdir)/$$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ 188 | rm -f $$tmpdir/$$lang.new.po; \ 189 | else \ 190 | if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ 191 | :; \ 192 | else \ 193 | echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ 194 | rm -f $$tmpdir/$$lang.new.po; \ 195 | exit 1; \ 196 | fi; \ 197 | fi; \ 198 | else \ 199 | echo "msgmerge for $$lang.gmo failed!"; \ 200 | rm -f $$tmpdir/$$lang.new.po; \ 201 | fi; \ 202 | done 203 | 204 | Makefile POTFILES: stamp-it 205 | @if test ! -f $@; then \ 206 | rm -f stamp-it; \ 207 | $(MAKE) stamp-it; \ 208 | fi 209 | 210 | stamp-it: Makefile.in.in $(top_builddir)/config.status POTFILES.in 211 | cd $(top_builddir) \ 212 | && CONFIG_FILES=$(subdir)/Makefile.in CONFIG_HEADERS= CONFIG_LINKS= \ 213 | $(SHELL) ./config.status 214 | 215 | # Tell versions [3.59,3.63) of GNU make not to export all variables. 216 | # Otherwise a system limit (for SysV at least) may be exceeded. 217 | .NOEXPORT: 218 | -------------------------------------------------------------------------------- /src/sbmgr.c: -------------------------------------------------------------------------------- 1 | /** 2 | * sbmgr.c 3 | * SBManager Widget implementation. 4 | * 5 | * Copyright (C) 2009-2010 Nikias Bassen 6 | * Copyright (C) 2009-2010 Martin Szulecki 7 | * 8 | * Licensed under the GNU General Public License Version 2 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more profile. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 23 | * USA 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "sbmgr.h" 32 | #include "device.h" 33 | #include "gui.h" 34 | #include "utility.h" 35 | 36 | static device_info_cb_t device_info_callback = NULL; 37 | static finished_cb_t finished_callback = NULL; 38 | 39 | GtkWidget *sbmgr_new() 40 | { 41 | if (!g_thread_supported()) 42 | g_thread_init(NULL); 43 | 44 | /* initialize device communication environment */ 45 | device_init(); 46 | 47 | /* Create the clutter widget and return it */ 48 | return gui_init(); 49 | } 50 | 51 | static gpointer gui_pages_load_cb(gpointer user_data) 52 | { 53 | const char *uuid = (const char*)user_data; 54 | gui_pages_load(uuid, device_info_callback, finished_callback); 55 | return NULL; 56 | } 57 | 58 | void sbmgr_load(const char *uuid, device_info_cb_t info_cb, finished_cb_t finished_cb) 59 | { 60 | /* load icons */ 61 | device_info_callback = info_cb; 62 | finished_callback = finished_cb; 63 | g_thread_create((GThreadFunc)gui_pages_load_cb, (gpointer)uuid, FALSE, NULL); 64 | } 65 | 66 | static gboolean iconstate_changed_v1(plist_t current_state, plist_t new_state) 67 | { 68 | if (!current_state || !new_state) { 69 | return FALSE; 70 | } 71 | /* compare new state with last saved state */ 72 | uint32_t cur_cnt = plist_array_get_size(current_state); 73 | uint32_t new_cnt = plist_array_get_size(new_state); 74 | debug_printf("%s: old %d, new %d\n", __func__, cur_cnt, new_cnt); 75 | if (cur_cnt != new_cnt) { 76 | /* number of pages has changed! */ 77 | debug_printf("%s: number of pages changed!\n", __func__); 78 | return TRUE; 79 | } 80 | 81 | /* now dig deeper */ 82 | uint32_t i; 83 | for (i = 0; i < new_cnt; i++) { 84 | plist_t cur_pp = plist_array_get_item(current_state, i); 85 | plist_t new_pp = plist_array_get_item(new_state, i); 86 | uint32_t cur_row_cnt = plist_array_get_size(cur_pp); 87 | uint32_t new_row_cnt = plist_array_get_size(new_pp); 88 | if (cur_row_cnt != new_row_cnt) { 89 | fprintf(stderr, "%s: number of rows on page %d changed: old %d, new %d, this is NOT expected!\n", __func__, i, cur_row_cnt, new_row_cnt); 90 | return FALSE; 91 | } 92 | uint32_t j; 93 | for (j = 0; j < cur_row_cnt; j++) { 94 | plist_t cur_row = plist_array_get_item(cur_pp, j); 95 | plist_t new_row = plist_array_get_item(new_pp, j); 96 | uint32_t cur_item_cnt = plist_array_get_size(cur_row); 97 | uint32_t new_item_cnt = plist_array_get_size(new_row); 98 | if (cur_item_cnt != new_item_cnt) { 99 | fprintf(stderr, "%s: number of items on page %d row %d changed: old %d, new %d, this is NOT expected!\n", __func__, i, j, cur_item_cnt, new_item_cnt); 100 | return FALSE; 101 | } 102 | uint32_t k; 103 | for (k = 0; k < cur_item_cnt; k++) { 104 | plist_t cur_node = plist_array_get_item(cur_row, k); 105 | plist_t new_node = plist_array_get_item(new_row, k); 106 | if (plist_get_node_type(cur_node) != plist_get_node_type(new_node)) { 107 | /* one is an icon, the other one empty. this is a change! */ 108 | return TRUE; 109 | } 110 | if (plist_get_node_type(cur_node) == PLIST_DICT) { 111 | /* ok, compare the displayIdentifier */ 112 | plist_t cur_di = plist_dict_get_item(cur_node, "displayIdentifier"); 113 | plist_t new_di = plist_dict_get_item(new_node, "displayIdentifier"); 114 | if (plist_compare_node_value(cur_di, new_di) == FALSE) { 115 | debug_printf("%s: page %d row %d item %d changed!\n", __func__, i, j, k); 116 | return TRUE; 117 | } 118 | } 119 | } 120 | } 121 | } 122 | 123 | /* no change found */ 124 | debug_printf("%s: no change!\n", __func__); 125 | return FALSE; 126 | } 127 | 128 | static gboolean iconstate_changed_v2(plist_t current_state, plist_t new_state) 129 | { 130 | if (!current_state || !new_state) { 131 | return FALSE; 132 | } 133 | 134 | /* compare new state with last saved state */ 135 | uint32_t cur_cnt = plist_array_get_size(current_state); 136 | uint32_t new_cnt = plist_array_get_size(new_state); 137 | debug_printf("%s: old %d, new %d\n", __func__, cur_cnt, new_cnt); 138 | if (cur_cnt != new_cnt) { 139 | /* number of pages has changed! */ 140 | debug_printf("%s: number of pages changed!\n", __func__); 141 | return TRUE; 142 | } 143 | 144 | /* now dig deeper */ 145 | uint32_t i; 146 | for (i = 0; i < new_cnt; i++) { 147 | plist_t cur_pp = plist_array_get_item(current_state, i); 148 | plist_t new_pp = plist_array_get_item(new_state, i); 149 | if (plist_get_node_type(plist_array_get_item(new_pp, 0)) == PLIST_ARRAY) { 150 | new_pp = plist_array_get_item(new_pp, 0); 151 | } 152 | if (plist_get_node_type(plist_array_get_item(cur_pp, 0)) == PLIST_ARRAY) { 153 | cur_pp = plist_array_get_item(cur_pp, 0); 154 | } 155 | 156 | uint32_t cur_item_cnt = plist_array_get_size(cur_pp); 157 | uint32_t new_item_cnt = plist_array_get_size(new_pp); 158 | if (cur_item_cnt != new_item_cnt) { 159 | fprintf(stderr, "%s: number of items on page %d changed: old %d, new %d\n", __func__, i, cur_item_cnt, new_item_cnt); 160 | return TRUE; 161 | } 162 | uint32_t k; 163 | for (k = 0; k < cur_item_cnt; k++) { 164 | plist_t cur_node = plist_array_get_item(cur_pp, k); 165 | plist_t new_node = plist_array_get_item(new_pp, k); 166 | if (plist_get_node_type(cur_node) == PLIST_DICT) { 167 | /* ok, compare the displayIdentifier */ 168 | plist_t cur_di = plist_dict_get_item(cur_node, "displayIdentifier"); 169 | plist_t new_di = plist_dict_get_item(new_node, "displayIdentifier"); 170 | if (!cur_di && !new_di) { 171 | cur_di = plist_dict_get_item(cur_node, "displayName"); 172 | new_di = plist_dict_get_item(new_node, "displayName"); 173 | if (plist_compare_node_value(cur_di, new_di) == FALSE) { 174 | debug_printf("%s: page %d folder item %d displayName changed!\n", __func__, i, k); 175 | return TRUE; 176 | } 177 | cur_di = plist_dict_get_item(cur_node, "iconLists"); 178 | new_di = plist_dict_get_item(new_node, "iconLists"); 179 | cur_di = plist_array_get_item(cur_di, 0); 180 | new_di = plist_array_get_item(new_di, 0); 181 | if (plist_array_get_size(cur_di) != plist_array_get_size(new_di)) { 182 | debug_printf("%s: page %d folder item %d subitem count changed!\n", __func__, i, k); 183 | return TRUE; 184 | } 185 | uint32_t j; 186 | for (j = 0; j < plist_array_get_size(cur_di); j++) { 187 | plist_t cur_si = plist_array_get_item(cur_di, j); 188 | plist_t new_si = plist_array_get_item(new_di, j); 189 | if (plist_compare_node_value(cur_si, new_si) == FALSE) { 190 | debug_printf("%s: page %d folder item %d subitem %d changed!\n", __func__, i, k, j); 191 | return TRUE; 192 | } 193 | } 194 | } else if ((!cur_di && new_di) || (cur_di && !new_di)) { 195 | debug_printf("%s: page %d item %d changed!\n", __func__, i, k); 196 | return TRUE; 197 | } else { 198 | if (plist_compare_node_value(cur_di, new_di) == FALSE) { 199 | debug_printf("%s: page %d item %d changed!\n", __func__, i, k); 200 | return TRUE; 201 | } 202 | } 203 | } 204 | } 205 | } 206 | 207 | /* no change found */ 208 | debug_printf("%s: no change!\n", __func__); 209 | return FALSE; 210 | } 211 | 212 | static gboolean iconstate_changed(plist_t current_state, plist_t new_state, const char *format_version) 213 | { 214 | if (format_version && (strcmp(format_version, "2") == 0)) { 215 | return iconstate_changed_v2(current_state, new_state); 216 | } else { 217 | return iconstate_changed_v1(current_state, new_state); 218 | } 219 | } 220 | 221 | void sbmgr_save(const char *uuid) 222 | { 223 | GError *error = NULL; 224 | sbservices_client_t sbc; 225 | uint32_t osversion = 0; 226 | 227 | sbc = device_sbs_new(uuid, &osversion, &error); 228 | 229 | if (error) { 230 | g_printerr("%s", error->message); 231 | g_error_free(error); 232 | error = NULL; 233 | } 234 | 235 | if (sbc) { 236 | plist_t current_state = NULL; 237 | const char *fmt_version = NULL; 238 | if (osversion >= 0x04000000) { 239 | fmt_version = "2"; 240 | } 241 | plist_t iconstate = gui_get_iconstate(fmt_version); 242 | if (iconstate) { 243 | device_sbs_get_iconstate(sbc, ¤t_state, fmt_version, &error); 244 | if (error) { 245 | g_printerr("%s", error->message); 246 | g_error_free(error); 247 | error = NULL; 248 | } 249 | if (iconstate_changed(current_state, iconstate, fmt_version) == TRUE) { 250 | device_sbs_set_iconstate(sbc, iconstate, &error); 251 | } 252 | if (current_state) { 253 | plist_free(current_state); 254 | } 255 | plist_free(iconstate); 256 | } 257 | device_sbs_free(sbc); 258 | } 259 | 260 | if (error) { 261 | g_printerr("%s", error->message); 262 | g_error_free(error); 263 | error = NULL; 264 | } 265 | } 266 | 267 | void sbmgr_cleanup() 268 | { 269 | gui_pages_free(); 270 | } 271 | 272 | void sbmgr_finalize() 273 | { 274 | sbmgr_cleanup(); 275 | gui_deinit(); 276 | } 277 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | /** 2 | * sbmanager -- Manage iPhone/iPod Touch SpringBoard icons from your computer! 3 | * 4 | * Copyright (C) 2009-2010 Nikias Bassen 5 | * Copyright (C) 2009-2010 Martin Szulecki 6 | * 7 | * Licensed under the GNU General Public License Version 2 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more profile. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 22 | * USA 23 | */ 24 | 25 | #ifdef HAVE_CONFIG_H 26 | #include /* for GETTEXT_PACKAGE */ 27 | #endif 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include "sbmgr.h" 45 | #include "utility.h" 46 | 47 | GtkWidget *main_window; 48 | GtkWidget *btn_reload; 49 | GtkWidget *btn_apply; 50 | 51 | char *match_uuid = NULL; 52 | char *current_uuid = NULL; 53 | 54 | static gboolean win_map_cb(GtkWidget *widget, GdkEvent *event, gpointer *data) 55 | { 56 | debug_printf("%s: mapped\n", __func__); 57 | 58 | return TRUE; 59 | } 60 | 61 | static void update_device_info_cb(const char *device_name, const char *device_type) 62 | { 63 | if (device_name) { 64 | gchar *wndtitle = g_strdup_printf("%s - " PACKAGE_NAME, device_name); 65 | gtk_window_set_title(GTK_WINDOW(main_window), wndtitle); 66 | g_free(wndtitle); 67 | } else { 68 | gtk_window_set_title(GTK_WINDOW(main_window), PACKAGE_NAME); 69 | } 70 | } 71 | 72 | static void finished_cb(gboolean success) 73 | { 74 | gtk_widget_set_sensitive(btn_reload, TRUE); 75 | gtk_widget_set_sensitive(btn_apply, TRUE); 76 | if (success) { 77 | printf("successfully loaded icons\n"); 78 | } else { 79 | printf("there was an error loading the icons\n"); 80 | } 81 | } 82 | 83 | static gboolean reload_button_clicked_cb(GtkButton *button, gpointer user_data) 84 | { 85 | gtk_widget_set_sensitive(btn_reload, FALSE); 86 | gtk_widget_set_sensitive(btn_apply, FALSE); 87 | sbmgr_load(current_uuid, update_device_info_cb, finished_cb); 88 | return TRUE; 89 | } 90 | 91 | static gboolean apply_button_clicked_cb(GtkButton *button, gpointer user_data) 92 | { 93 | gtk_widget_set_sensitive(btn_reload, FALSE); 94 | gtk_widget_set_sensitive(btn_apply, FALSE); 95 | sbmgr_save(current_uuid); 96 | gtk_widget_set_sensitive(btn_reload, TRUE); 97 | gtk_widget_set_sensitive(btn_apply, TRUE); 98 | return TRUE; 99 | } 100 | 101 | static gboolean info_button_clicked_cb(GtkButton *button, gpointer user_data) 102 | { 103 | const gchar *authors[] = { 104 | "Nikias Bassen ", 105 | "Martin Szulecki ", 106 | NULL 107 | }; 108 | const gchar *copyright = "Copyright © 2009-2010 Nikias Bassen, Martin Szulecki; All Rights Reserved."; 109 | const gchar *program_name = PACKAGE_NAME; 110 | const gchar *version = PACKAGE_VERSION; 111 | const gchar *comments = _("Manage iPhone/iPod Touch SpringBoard from the computer"); 112 | const gchar *website = "http://cgit.sukimashita.com/sbmanager.git"; 113 | const gchar *website_label = _("Project Site"); 114 | const gchar *translators = 115 | "Español: Itxaka Serrano\n" 116 | "Français: Christophe Fergeau\n" 117 | "Italiano: Mario Polino\n" 118 | "日本語: Koichi Akabe\n" 119 | ; 120 | 121 | gtk_show_about_dialog(GTK_WINDOW(main_window), 122 | "authors", authors, 123 | "copyright", copyright, 124 | "program-name", program_name, 125 | "version", version, 126 | "comments", comments, 127 | "website", website, 128 | "website-label", website_label, 129 | "translator-credits", translators, 130 | NULL); 131 | return TRUE; 132 | } 133 | 134 | static void quit_program_cb(GtkWidget *widget, gpointer user_data) 135 | { 136 | /* cleanup */ 137 | sbmgr_finalize(); 138 | idevice_event_unsubscribe(); 139 | gtk_main_quit(); 140 | } 141 | 142 | static gboolean quit_button_clicked_cb(GtkButton *button, gpointer user_data) 143 | { 144 | quit_program_cb(GTK_WIDGET(button), user_data); 145 | return TRUE; 146 | } 147 | 148 | static void gui_error_dialog(const gchar *string) 149 | { 150 | GtkWidget *dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW(main_window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", _("Error")); 151 | gtk_window_set_title(GTK_WINDOW(dialog), PACKAGE_NAME); 152 | gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s", string); 153 | g_signal_connect_swapped (dialog, "response", G_CALLBACK(gtk_widget_destroy), dialog); 154 | gtk_widget_show(dialog); 155 | } 156 | 157 | static gpointer device_add_cb(gpointer user_data) 158 | { 159 | const char *uuid = (const char*)user_data; 160 | sbmgr_load(uuid, update_device_info_cb, finished_cb); 161 | return NULL; 162 | } 163 | 164 | static void device_event_cb(const idevice_event_t *event, void *user_data) 165 | { 166 | if (event->event == IDEVICE_DEVICE_ADD) { 167 | if (!current_uuid && (!match_uuid || !strcasecmp(match_uuid, event->uuid))) { 168 | debug_printf("Device add event: adding device %s\n", event->uuid); 169 | current_uuid = g_strdup(event->uuid); 170 | g_thread_create(device_add_cb, current_uuid, FALSE, NULL); 171 | } else { 172 | debug_printf("Device add event: ignoring device %s\n", event->uuid); 173 | } 174 | } else if (event->event == IDEVICE_DEVICE_REMOVE) { 175 | if (current_uuid && !strcasecmp(current_uuid, event->uuid)) { 176 | debug_printf("Device remove event: removing device %s\n", event->uuid); 177 | free(current_uuid); 178 | current_uuid = NULL; 179 | sbmgr_cleanup(); 180 | } else { 181 | debug_printf("Device remove event: ignoring device %s\n", event->uuid); 182 | } 183 | } 184 | } 185 | 186 | static void wnd_init() 187 | { 188 | /* Create the clutter widget */ 189 | GtkWidget *sbmgr_widget = sbmgr_new(); 190 | if (!sbmgr_widget) { 191 | return; 192 | } 193 | 194 | main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 195 | gtk_window_set_resizable(GTK_WINDOW(main_window), FALSE); 196 | 197 | gtk_window_set_title(GTK_WINDOW(main_window), PACKAGE_NAME); 198 | 199 | GtkWidget *vbox = gtk_vbox_new(FALSE, 6); 200 | gtk_container_add(GTK_CONTAINER(main_window), vbox); 201 | gtk_widget_show(vbox); 202 | 203 | /* create a toolbar */ 204 | GtkWidget *toolbar = gtk_toolbar_new(); 205 | gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0); 206 | 207 | btn_reload = (GtkWidget*)gtk_tool_button_new_from_stock(GTK_STOCK_REFRESH); 208 | gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(btn_reload), _("Reload icons from device")); 209 | gtk_toolbar_insert(GTK_TOOLBAR(toolbar), GTK_TOOL_ITEM(btn_reload), -1); 210 | 211 | btn_apply = (GtkWidget*)gtk_tool_button_new_from_stock(GTK_STOCK_APPLY); 212 | gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(btn_apply), _("Upload changes to device")); 213 | gtk_toolbar_insert(GTK_TOOLBAR(toolbar), GTK_TOOL_ITEM(btn_apply), -1); 214 | 215 | GtkToolItem *btn_info = gtk_tool_button_new_from_stock(GTK_STOCK_INFO); 216 | gtk_tool_item_set_tooltip_text(btn_info, _("Get info about this cool program")); 217 | gtk_toolbar_insert(GTK_TOOLBAR(toolbar), btn_info, -1); 218 | 219 | GtkToolItem *spacer = gtk_tool_item_new(); 220 | gtk_tool_item_set_expand(spacer, TRUE); 221 | gtk_toolbar_insert(GTK_TOOLBAR(toolbar), spacer, -1); 222 | 223 | GtkToolItem *btn_quit = gtk_tool_button_new_from_stock(GTK_STOCK_QUIT); 224 | gtk_tool_item_set_tooltip_text(btn_quit, _("Quit this program")); 225 | gtk_toolbar_insert(GTK_TOOLBAR(toolbar), btn_quit, -1); 226 | 227 | gtk_widget_set_sensitive(btn_reload, FALSE); 228 | gtk_widget_set_sensitive(btn_apply, FALSE); 229 | gtk_widget_show(toolbar); 230 | 231 | /* set up signal handlers */ 232 | g_signal_connect(btn_reload, "clicked", G_CALLBACK(reload_button_clicked_cb), NULL); 233 | g_signal_connect(btn_apply, "clicked", G_CALLBACK(apply_button_clicked_cb), NULL); 234 | g_signal_connect(btn_info, "clicked", G_CALLBACK(info_button_clicked_cb), NULL); 235 | g_signal_connect(btn_quit, "clicked", G_CALLBACK(quit_button_clicked_cb), NULL); 236 | 237 | /* insert sbmgr widget */ 238 | gtk_box_pack_start(GTK_BOX(vbox), sbmgr_widget, TRUE, TRUE, 0); 239 | gtk_widget_show(sbmgr_widget); 240 | gtk_widget_grab_focus(sbmgr_widget); 241 | 242 | /* create a statusbar */ 243 | /* statusbar = gtk_statusbar_new(); 244 | gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(statusbar), FALSE); 245 | gtk_box_pack_start(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0); 246 | gtk_widget_show(statusbar); 247 | */ 248 | /* attach to window signals */ 249 | g_signal_connect(G_OBJECT(main_window), "map-event", G_CALLBACK(win_map_cb), NULL); 250 | 251 | /* Show the window. This also sets the stage's bounding box. */ 252 | gtk_widget_show_all(GTK_WIDGET(main_window)); 253 | 254 | g_set_printerr_handler((GPrintFunc)gui_error_dialog); 255 | 256 | /* Stop the application when the window is closed */ 257 | g_signal_connect(main_window, "hide", G_CALLBACK(quit_program_cb), NULL); 258 | 259 | /* get notified when plug in/out events occur */ 260 | idevice_event_subscribe(device_event_cb, NULL); 261 | } 262 | 263 | /* main */ 264 | static void print_usage(int argc, char **argv) 265 | { 266 | char *name = NULL; 267 | 268 | name = strrchr(argv[0], '/'); 269 | printf("Usage: %s [OPTIONS]\n", (name ? name + 1 : argv[0])); 270 | printf("Manage SpringBoard icons of an iPhone/iPod Touch.\n\n"); 271 | printf(" -d, --debug\t\tenable communication debugging\n"); 272 | printf(" -D, --debug-app\tenable application debug messages\n"); 273 | printf(" -u, --uuid UUID\ttarget specific device by its 40-digit device UUID\n"); 274 | printf(" -h, --help\t\tprints usage information\n"); 275 | printf("\n"); 276 | } 277 | 278 | int main(int argc, char **argv) 279 | { 280 | int i; 281 | 282 | /* parse cmdline args */ 283 | for (i = 1; i < argc; i++) { 284 | if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { 285 | idevice_set_debug_level(1); 286 | continue; 287 | } else if (!strcmp(argv[i], "-D") || !strcmp(argv[i], "--debug-app")) { 288 | set_debug(TRUE); 289 | continue; 290 | } else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--uuid")) { 291 | i++; 292 | if (!argv[i] || (strlen(argv[i]) != 40)) { 293 | print_usage(argc, argv); 294 | return 0; 295 | } 296 | match_uuid = g_strndup(argv[i], 40); 297 | continue; 298 | } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { 299 | print_usage(argc, argv); 300 | return 0; 301 | } else { 302 | print_usage(argc, argv); 303 | return 0; 304 | } 305 | } 306 | 307 | /* Create the window and some child widgets */ 308 | wnd_init(); 309 | 310 | /* Start the main loop, so we can respond to events */ 311 | gtk_main(); 312 | 313 | return 0; 314 | } 315 | -------------------------------------------------------------------------------- /src/device.c: -------------------------------------------------------------------------------- 1 | /** 2 | * device.c 3 | * Device communication functions. 4 | * 5 | * Copyright (C) 2009-2010 Nikias Bassen 6 | * Copyright (C) 2009-2010 Martin Szulecki 7 | * 8 | * Licensed under the GNU General Public License Version 2 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more profile. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 23 | * USA 24 | */ 25 | #ifdef HAVE_CONFIG_H 26 | #include /* for GETTEXT_PACKAGE */ 27 | #endif 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | #include "device.h" 40 | 41 | static GMutex *idevice_mutex = NULL; 42 | static GQuark device_domain = 0; 43 | 44 | void device_init() 45 | { 46 | idevice_mutex = g_mutex_new(); 47 | device_domain = g_quark_from_string("libimobiledevice"); 48 | } 49 | 50 | static gboolean device_connect(const char *uuid, idevice_t *phone, lockdownd_client_t *client, GError **error) { 51 | gboolean res = FALSE; 52 | 53 | if (!client || !phone) { 54 | return res; 55 | } 56 | 57 | if (IDEVICE_E_SUCCESS != idevice_new(phone, uuid)) { 58 | *error = g_error_new(device_domain, ENODEV, _("No device found, is it plugged in?")); 59 | return res; 60 | } 61 | 62 | if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(*phone, client, "sbmanager")) { 63 | *error = g_error_new(device_domain, EIO, _("Could not connect to lockdownd!")); 64 | return res; 65 | } 66 | 67 | res = TRUE; 68 | 69 | return res; 70 | } 71 | 72 | sbservices_client_t device_sbs_new(const char *uuid, uint32_t *osversion, GError **error) 73 | { 74 | sbservices_client_t sbc = NULL; 75 | idevice_t phone = NULL; 76 | lockdownd_client_t client = NULL; 77 | uint16_t port = 0; 78 | 79 | printf("%s: %s\n", __func__, uuid); 80 | 81 | g_mutex_lock(idevice_mutex); 82 | if (!device_connect(uuid, &phone, &client, error)) { 83 | goto leave_cleanup; 84 | } 85 | 86 | plist_t version = NULL; 87 | if (osversion && lockdownd_get_value(client, NULL, "ProductVersion", &version) == LOCKDOWN_E_SUCCESS) { 88 | if (plist_get_node_type(version) == PLIST_STRING) { 89 | char *version_string = NULL; 90 | plist_get_string_val(version, &version_string); 91 | if (version_string) { 92 | /* parse version */ 93 | int maj = 0; 94 | int min = 0; 95 | int rev = 0; 96 | sscanf(version_string, "%d.%d.%d", &maj, &min, &rev); 97 | free(version_string); 98 | *osversion = ((maj & 0xFF) << 24) + ((min & 0xFF) << 16) + ((rev & 0xFF) << 8); 99 | } 100 | } 101 | } 102 | 103 | if ((lockdownd_start_service(client, "com.apple.springboardservices", &port) != LOCKDOWN_E_SUCCESS) || !port) { 104 | if (error) 105 | *error = g_error_new(device_domain, EIO, _("Could not start com.apple.springboardservices service! Remind that this feature is only supported in OS 3.1 and later!")); 106 | goto leave_cleanup; 107 | } 108 | if (sbservices_client_new(phone, port, &sbc) != SBSERVICES_E_SUCCESS) { 109 | if (error) 110 | *error = g_error_new(device_domain, EIO, _("Could not connect to springboardservices!")); 111 | goto leave_cleanup; 112 | } 113 | 114 | leave_cleanup: 115 | if (client) { 116 | lockdownd_client_free(client); 117 | } 118 | idevice_free(phone); 119 | g_mutex_unlock(idevice_mutex); 120 | 121 | return sbc; 122 | } 123 | 124 | void device_sbs_free(sbservices_client_t sbc) 125 | { 126 | if (sbc) { 127 | sbservices_client_free(sbc); 128 | } 129 | } 130 | 131 | gboolean device_sbs_get_iconstate(sbservices_client_t sbc, plist_t *iconstate, const char *format_version, GError **error) 132 | { 133 | plist_t iconstate_loc = NULL; 134 | gboolean ret = FALSE; 135 | 136 | *iconstate = NULL; 137 | if (sbc) { 138 | sbservices_error_t err; 139 | #ifdef HAVE_LIBIMOBILEDEVICE_1_1 140 | err = sbservices_get_icon_state(sbc, &iconstate_loc, format_version); 141 | #else 142 | err = sbservices_get_icon_state(sbc, &iconstate_loc); 143 | #endif 144 | if (err != SBSERVICES_E_SUCCESS || !iconstate_loc) { 145 | if (error) 146 | *error = g_error_new(device_domain, EIO, _("Could not get icon state!")); 147 | goto leave_cleanup; 148 | } 149 | if (plist_get_node_type(iconstate_loc) != PLIST_ARRAY) { 150 | if (error) 151 | *error = g_error_new(device_domain, EIO, _("icon state is not an array as expected!")); 152 | goto leave_cleanup; 153 | } 154 | *iconstate = iconstate_loc; 155 | ret = TRUE; 156 | } 157 | 158 | leave_cleanup: 159 | if ((ret == FALSE) && iconstate_loc) { 160 | plist_free(iconstate_loc); 161 | } 162 | return ret; 163 | } 164 | 165 | gboolean device_sbs_save_icon(sbservices_client_t sbc, char *display_identifier, char *filename, GError **error) 166 | { 167 | gboolean res = FALSE; 168 | char *png = NULL; 169 | uint64_t pngsize = 0; 170 | 171 | if ((sbservices_get_icon_pngdata(sbc, display_identifier, &png, &pngsize) == SBSERVICES_E_SUCCESS) && (pngsize > 0)) { 172 | /* save png icon to disk */ 173 | res = g_file_set_contents (filename, png, pngsize, error); 174 | } else { 175 | if (error) 176 | *error = g_error_new(device_domain, EIO, _("Could not get icon png data for '%s'"), display_identifier); 177 | } 178 | if (png) { 179 | free(png); 180 | } 181 | return res; 182 | } 183 | 184 | gboolean device_sbs_set_iconstate(sbservices_client_t sbc, plist_t iconstate, GError **error) 185 | { 186 | gboolean result = FALSE; 187 | 188 | printf("About to upload new iconstate...\n"); 189 | 190 | if (sbc) { 191 | if (sbservices_set_icon_state(sbc, iconstate) != SBSERVICES_E_SUCCESS) { 192 | if (error) 193 | *error = g_error_new(device_domain, EIO, _("Could not set new icon state!")); 194 | goto leave_cleanup; 195 | } 196 | 197 | printf("Successfully uploaded new iconstate\n"); 198 | result = TRUE; 199 | } 200 | 201 | leave_cleanup: 202 | return result; 203 | } 204 | 205 | #ifdef HAVE_LIBIMOBILEDEVICE_1_1 206 | char *device_sbs_save_wallpaper(sbservices_client_t sbc, const char *uuid, GError **error) 207 | { 208 | char *res = NULL; 209 | char *png = NULL; 210 | uint64_t pngsize = 0; 211 | 212 | if ((sbservices_get_home_screen_wallpaper_pngdata(sbc, &png, &pngsize) == SBSERVICES_E_SUCCESS) && (pngsize > 0)) { 213 | /* save png icon to disk */ 214 | char *path; 215 | char *filename; 216 | 217 | path = g_build_filename (g_get_user_cache_dir (), 218 | "libimobiledevice", 219 | "wallpaper", NULL); 220 | g_mkdir_with_parents (path, 0755); 221 | g_free (path); 222 | 223 | filename = g_strdup_printf ("%s.png", uuid); 224 | path = g_build_filename (g_get_user_cache_dir (), 225 | "libimobiledevice", 226 | "wallpaper", 227 | filename, NULL); 228 | g_free (filename); 229 | 230 | if (g_file_set_contents (path, png, pngsize, error) == FALSE) { 231 | g_free (filename); 232 | free (png); 233 | return NULL; 234 | } 235 | res = path; 236 | } else { 237 | if (error) 238 | *error = g_error_new(device_domain, EIO, _("Could not get wallpaper png data")); 239 | } 240 | if (png) { 241 | free(png); 242 | } 243 | return res; 244 | } 245 | #endif 246 | 247 | device_info_t device_info_new() 248 | { 249 | device_info_t device_info = g_new0(struct device_info_int, 1); 250 | 251 | /* initialize default values */ 252 | device_info->home_screen_icon_columns = 4; 253 | device_info->home_screen_icon_dock_max_count = 4; 254 | device_info->home_screen_icon_height = 57; 255 | device_info->home_screen_icon_rows = 4; 256 | device_info->home_screen_icon_width = 57; 257 | device_info->icon_folder_columns = 4; 258 | device_info->icon_folder_max_pages = 1; 259 | device_info->icon_folder_rows = 3; 260 | device_info->icon_state_saves = 1; 261 | 262 | return device_info; 263 | } 264 | 265 | void device_info_free(device_info_t device_info) 266 | { 267 | if (device_info) { 268 | if (device_info->uuid) { 269 | free(device_info->uuid); 270 | } 271 | if (device_info->device_name) { 272 | free(device_info->device_name); 273 | } 274 | if (device_info->device_type) { 275 | free(device_info->device_type); 276 | } 277 | free(device_info); 278 | } 279 | } 280 | 281 | static guint battery_info_get_current_capacity(plist_t battery_info) 282 | { 283 | uint64_t current_capacity = 0; 284 | plist_t node = NULL; 285 | 286 | if (battery_info == NULL) 287 | return (guint)current_capacity; 288 | 289 | node = plist_dict_get_item(battery_info, "BatteryCurrentCapacity"); 290 | if (node != NULL) { 291 | plist_get_uint_val(node, ¤t_capacity); 292 | } 293 | return (guint)current_capacity; 294 | } 295 | 296 | gboolean device_poll_battery_capacity(const char *uuid, device_info_t *device_info, GError **error) { 297 | plist_t node = NULL; 298 | idevice_t phone = NULL; 299 | lockdownd_client_t client = NULL; 300 | gboolean res = FALSE; 301 | 302 | printf("%s: %s\n", __func__, uuid); 303 | 304 | if (!device_info) { 305 | return res; 306 | } 307 | 308 | printf("%s\n", __func__); 309 | 310 | g_mutex_lock(idevice_mutex); 311 | if (!device_connect(uuid, &phone, &client, error)) { 312 | goto leave_cleanup; 313 | } 314 | 315 | if (!*device_info) { 316 | /* make new device info */ 317 | *device_info = device_info_new(); 318 | } 319 | 320 | /* get current battery capacity */ 321 | node = NULL; 322 | lockdownd_get_value(client, "com.apple.mobile.battery", NULL, &node); 323 | (*device_info)->battery_capacity = battery_info_get_current_capacity(node); 324 | plist_free(node); 325 | 326 | res = TRUE; 327 | 328 | leave_cleanup: 329 | if (client) { 330 | lockdownd_client_free(client); 331 | } 332 | idevice_free(phone); 333 | g_mutex_unlock(idevice_mutex); 334 | 335 | return res; 336 | } 337 | 338 | static void device_dump_info(device_info_t info) { 339 | printf("%s: Device Information\n", __func__); 340 | 341 | printf("%s: UUID: %s\n", __func__, info->uuid); 342 | printf("%s: Name: %s\n", __func__, info->device_name); 343 | printf("%s: Type: %s\n", __func__, info->device_type); 344 | 345 | printf("%s: Battery\n", __func__); 346 | printf("%s: PollInterval: %d\n", __func__, info->battery_poll_interval); 347 | printf("%s: CurrentCapacity: %d\n", __func__, info->battery_capacity); 348 | 349 | printf("%s: HomeScreen Settings\n", __func__); 350 | 351 | printf("%s: IconColumns: %d\n", __func__, info->home_screen_icon_columns); 352 | printf("%s: IconRows: %d\n", __func__, info->home_screen_icon_rows); 353 | printf("%s: IconDockMaxCount: %d\n", __func__, info->home_screen_icon_dock_max_count); 354 | printf("%s: IconWidth: %d\n", __func__, info->home_screen_icon_width); 355 | printf("%s: IconHeight: %d\n", __func__, info->home_screen_icon_height); 356 | 357 | printf("%s: IconFolder Settings\n", __func__); 358 | printf("%s: IconWidth: %d\n", __func__, info->home_screen_icon_width); 359 | printf("%s: IconHeight: %d\n", __func__, info->home_screen_icon_height); 360 | } 361 | 362 | gboolean device_get_info(const char *uuid, device_info_t *device_info, GError **error) 363 | { 364 | uint8_t boolean = FALSE; 365 | uint64_t integer = 60; 366 | plist_t node = NULL; 367 | idevice_t phone = NULL; 368 | lockdownd_client_t client = NULL; 369 | gboolean res = FALSE; 370 | 371 | printf("%s: %s\n", __func__, uuid); 372 | 373 | if (!device_info) { 374 | return res; 375 | } 376 | 377 | printf("%s\n", __func__); 378 | 379 | g_mutex_lock(idevice_mutex); 380 | if (!device_connect(uuid, &phone, &client, error)) { 381 | goto leave_cleanup; 382 | } 383 | 384 | if (!*device_info) { 385 | /* make new device info */ 386 | *device_info = device_info_new(); 387 | } 388 | 389 | (*device_info)->uuid = strdup(uuid); 390 | 391 | if ((*device_info)->device_name) { 392 | free((*device_info)->device_name); 393 | (*device_info)->device_name = NULL; 394 | } 395 | if ((*device_info)->device_type) { 396 | free((*device_info)->device_type); 397 | (*device_info)->device_type = NULL; 398 | } 399 | 400 | /* get device name */ 401 | lockdownd_get_device_name(client, &((*device_info)->device_name)); 402 | 403 | /* get device type */ 404 | lockdownd_get_value(client, NULL, "ProductType", &node); 405 | if (node) { 406 | char *devtype = NULL; 407 | const char *devtypes[18][2] = { 408 | {"iPhone1,1", "iPhone"}, 409 | {"iPhone1,2", "iPhone 3G"}, 410 | {"iPhone2,1", "iPhone 3GS"}, 411 | {"iPhone3,1", "iPhone 4"}, 412 | {"iPhone3,3", "iPhone 4 CDMA"}, 413 | {"iPhone4,1", "iPhone 4S"}, 414 | {"iPad1,1", "iPad"}, 415 | {"iPad2,1", "iPad 2"}, 416 | {"iPad2,2", "iPad 2 3G GSM"}, 417 | {"iPad2,3", "iPad 2 3G CDMA"}, 418 | {"iPad2,4", "iPad"}, 419 | {"iPad3,1", "iPad (3rd Gen)"}, 420 | {"iPad3,2", "iPad 4G LTE (3rd Gen)"}, 421 | {"iPad3,3", "iPad 4G LTE (3rd Gen)"}, 422 | {"iPod1,1", "iPod Touch"}, 423 | {"iPod2,1", "iPod Touch (2G)"}, 424 | {"iPod3,1", "iPod Touch (3G)"}, 425 | {"iPod4,1", "iPod Touch (4G)"} 426 | }; 427 | plist_get_string_val(node, &devtype); 428 | if (devtype) { 429 | int i; 430 | for (i = 0; i < 6; i++) { 431 | if (g_str_equal(devtypes[i][0], devtype)) { 432 | (*device_info)->device_type = g_strdup(devtypes[i][1]); 433 | break; 434 | } 435 | } 436 | } 437 | plist_free(node); 438 | } 439 | 440 | /* get layout information */ 441 | node = NULL; 442 | plist_t value = NULL; 443 | lockdownd_get_value(client, "com.apple.mobile.iTunes", NULL, &node); 444 | 445 | value = plist_dict_get_item(node, "HomeScreenIconColumns"); 446 | plist_get_uint_val(value, &integer); 447 | (*device_info)->home_screen_icon_columns = (guint)integer; 448 | 449 | value = plist_dict_get_item(node, "HomeScreenIconDockMaxCount"); 450 | plist_get_uint_val(value, &integer); 451 | (*device_info)->home_screen_icon_dock_max_count = (guint)integer; 452 | 453 | value = plist_dict_get_item(node, "HomeScreenIconHeight"); 454 | plist_get_uint_val(value, &integer); 455 | (*device_info)->home_screen_icon_height = (guint)integer; 456 | 457 | value = plist_dict_get_item(node, "HomeScreenIconRows"); 458 | plist_get_uint_val(value, &integer); 459 | (*device_info)->home_screen_icon_rows = (guint)integer; 460 | 461 | value = plist_dict_get_item(node, "HomeScreenIconWidth"); 462 | plist_get_uint_val(value, &integer); 463 | (*device_info)->home_screen_icon_width = (guint)integer; 464 | 465 | value = plist_dict_get_item(node, "IconFolderColumns"); 466 | plist_get_uint_val(value, &integer); 467 | (*device_info)->icon_folder_columns = (guint)integer; 468 | 469 | value = plist_dict_get_item(node, "IconFolderMaxPages"); 470 | plist_get_uint_val(value, &integer); 471 | (*device_info)->icon_folder_max_pages = (guint)integer; 472 | 473 | value = plist_dict_get_item(node, "IconFolderRows"); 474 | plist_get_uint_val(value, &integer); 475 | (*device_info)->icon_folder_rows = (guint)integer; 476 | 477 | value = plist_dict_get_item(node, "IconStateSaves"); 478 | plist_get_bool_val(value, &boolean); 479 | (*device_info)->icon_state_saves = (gboolean)boolean; 480 | 481 | /* get battery poll interval */ 482 | value = plist_dict_get_item(node, "BatteryPollInterval"); 483 | plist_get_uint_val(value, &integer); 484 | (*device_info)->battery_poll_interval = (guint)integer; 485 | 486 | plist_free(node); 487 | value = NULL; 488 | 489 | /* get current battery capacity */ 490 | node = NULL; 491 | lockdownd_get_value(client, "com.apple.mobile.battery", NULL, &node); 492 | (*device_info)->battery_capacity = battery_info_get_current_capacity(node); 493 | plist_free(node); 494 | 495 | res = TRUE; 496 | 497 | device_dump_info((*device_info)); 498 | 499 | leave_cleanup: 500 | if (client) { 501 | lockdownd_client_free(client); 502 | } 503 | idevice_free(phone); 504 | g_mutex_unlock(idevice_mutex); 505 | 506 | return res; 507 | } 508 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /src/gui.c: -------------------------------------------------------------------------------- 1 | /** 2 | * gui.c 3 | * GUI implementations. 4 | * 5 | * Copyright (C) 2009-2010 Nikias Bassen 6 | * Copyright (C) 2009-2010 Martin Szulecki 7 | * 8 | * Licensed under the GNU General Public License Version 2 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more profile. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 23 | * USA 24 | */ 25 | 26 | #ifdef HAVE_CONFIG_H 27 | #include /* for GETTEXT_PACKAGE */ 28 | #endif 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include "sbmgr.h" 44 | #include "utility.h" 45 | #include "device.h" 46 | #include "sbitem.h" 47 | #include "gui.h" 48 | 49 | #define MIN(a, b) (((a) < (b)) ? (a) : (b)) 50 | #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 51 | 52 | #define STAGE_WIDTH 320 53 | #define STAGE_HEIGHT 480 54 | #define DOCK_HEIGHT 90 55 | #define MAX_PAGE_ITEMS (gint)(device_info->home_screen_icon_rows*device_info->home_screen_icon_columns+device_info->home_screen_icon_dock_max_count) 56 | #define ICON_SPACING 18 57 | #define PAGE_X_OFFSET(i) ((gfloat)(i)*(gfloat)(stage_area.x2)) 58 | 59 | #define ICON_MOVEMENT_DURATION 250 60 | #define FOLDER_ANIM_DURATION 500 61 | 62 | const char CLOCK_FONT[] = "FreeSans Bold 12px"; 63 | ClutterColor clock_text_color = { 255, 255, 255, 210 }; 64 | 65 | const char ITEM_FONT[] = "FreeSans Bold 10px"; 66 | ClutterColor item_text_color = { 255, 255, 255, 210 }; 67 | ClutterColor dock_item_text_color = { 255, 255, 255, 255 }; 68 | ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff }; /* Black */ 69 | ClutterColor battery_color = { 0xff, 0xff, 0xff, 0x9f }; 70 | ClutterColor spinner_color = { 0xff, 0xff, 0xff, 0xf0 }; 71 | ClutterColor label_shadow_color = { 0x00, 0x00, 0x00, 0xe0 }; 72 | 73 | const char FOLDER_LARGE_FONT[] = "FreeSans Bold 18px"; 74 | 75 | GtkWidget *clutter_gtk_widget; 76 | 77 | ClutterActorBox stage_area = { 0.0, 0.0, STAGE_WIDTH, STAGE_HEIGHT }; 78 | ClutterActorBox dock_area = { 0.0, STAGE_HEIGHT - DOCK_HEIGHT, STAGE_WIDTH, STAGE_HEIGHT }; 79 | ClutterActorBox sb_area = { 0.0, ICON_SPACING, STAGE_WIDTH, STAGE_HEIGHT - DOCK_HEIGHT - ICON_SPACING }; 80 | ClutterActorBox left_trigger = { -30.0, ICON_SPACING, -8.0, STAGE_HEIGHT - DOCK_HEIGHT - ICON_SPACING }; 81 | ClutterActorBox right_trigger = { STAGE_WIDTH + 8.0, ICON_SPACING, STAGE_WIDTH + 30.0, STAGE_HEIGHT - DOCK_HEIGHT - ICON_SPACING }; 82 | 83 | ClutterActor *stage = NULL; 84 | ClutterActor *wallpaper = NULL; 85 | ClutterActor *the_dock = NULL; 86 | ClutterActor *the_sb = NULL; 87 | ClutterActor *type_label = NULL; 88 | ClutterActor *clock_label = NULL; 89 | ClutterActor *battery_level = NULL; 90 | ClutterActor *page_indicator = NULL; 91 | ClutterActor *page_indicator_group = NULL; 92 | ClutterActor *fade_rectangle = NULL; 93 | ClutterActor *spinner = NULL; 94 | ClutterActor *icon_shadow = NULL; 95 | ClutterTimeline *spinner_timeline = NULL; 96 | ClutterTimeline *clock_timeline = NULL; 97 | 98 | GMutex *selected_mutex = NULL; 99 | SBItem *selected_item = NULL; 100 | 101 | SBItem *selected_folder = NULL; 102 | 103 | ClutterActor *folder_marker = NULL; 104 | 105 | ClutterActor *aniupper = NULL; 106 | ClutterActor *anilower = NULL; 107 | ClutterActor *folder = NULL; 108 | gfloat split_pos = 0.0; 109 | 110 | GMutex *icon_loader_mutex = NULL; 111 | static int icons_loaded = 0; 112 | static int total_icons = 0; 113 | 114 | gfloat start_x = 0.0; 115 | gfloat start_y = 0.0; 116 | 117 | gboolean move_left = TRUE; 118 | 119 | GList *dockitems = NULL; 120 | GList *sbpages = NULL; 121 | 122 | guint num_dock_items = 0; 123 | 124 | sbservices_client_t sbc = NULL; 125 | uint32_t osversion = 0; 126 | device_info_t device_info = NULL; 127 | 128 | static finished_cb_t finished_callback = NULL; 129 | static device_info_cb_t device_info_callback = NULL; 130 | 131 | int current_page = 0; 132 | struct timeval last_page_switch; 133 | 134 | static int gui_deinitialized = 0; 135 | static int clutter_threads_initialized = 0; 136 | static int clutter_initialized = 0; 137 | 138 | static void gui_page_indicator_group_add(GList *page, int page_index); 139 | static void gui_page_align_icons(guint page_num, gboolean animated); 140 | static void gui_folder_align_icons(SBItem *item, gboolean animated); 141 | 142 | /* helper */ 143 | static void sbpage_free(GList *sbitems, gpointer data) 144 | { 145 | if (sbitems) { 146 | g_list_foreach(sbitems, (GFunc) (g_func_sbitem_free), NULL); 147 | g_list_free(sbitems); 148 | clutter_group_remove_all(CLUTTER_GROUP(page_indicator_group)); 149 | } 150 | } 151 | 152 | static void pages_free() 153 | { 154 | if (sbpages) { 155 | g_list_foreach(sbpages, (GFunc)(sbpage_free), NULL); 156 | g_list_free(sbpages); 157 | sbpages = NULL; 158 | } 159 | if (dockitems) { 160 | sbpage_free(dockitems, NULL); 161 | dockitems = NULL; 162 | } 163 | if (wallpaper) { 164 | clutter_actor_destroy(wallpaper); 165 | wallpaper = NULL; 166 | item_text_color.alpha = 210; 167 | } 168 | } 169 | 170 | static gboolean item_enable(gpointer item) 171 | { 172 | if (item) { 173 | ((SBItem*)item)->enabled = TRUE; 174 | } 175 | return FALSE; 176 | } 177 | 178 | static void clutter_actor_get_abs_center(ClutterActor *actor, gfloat *center_x, gfloat *center_y) 179 | { 180 | *center_x = 0.0; 181 | *center_y = 0.0; 182 | if (!actor) 183 | return; 184 | clutter_actor_get_scale_center(actor, center_x, center_y); 185 | *center_x += clutter_actor_get_x(actor); 186 | *center_y += clutter_actor_get_y(actor); 187 | } 188 | 189 | static GList *iconlist_insert_item_at(GList *iconlist, SBItem *newitem, gfloat item_x, gfloat item_y, int pageindex, int icons_per_row) 190 | { 191 | if (!newitem) { 192 | return iconlist; 193 | } 194 | 195 | debug_printf("%s: count items %d\n", __func__, g_list_length(iconlist)); 196 | 197 | if (!iconlist) { 198 | debug_printf("%s: appending item\n", __func__); 199 | /* for empty lists just add the element */ 200 | return g_list_append(iconlist, newitem); 201 | } 202 | gint i; 203 | gint count = g_list_length(iconlist); 204 | gint newpos = count; 205 | if (count <= 0) { 206 | return iconlist; 207 | } 208 | 209 | gfloat xpageoffset = PAGE_X_OFFSET(pageindex); 210 | 211 | gfloat spacing = ICON_SPACING; 212 | if (icons_per_row > (gint)device_info->home_screen_icon_columns) { 213 | spacing = 3; 214 | } 215 | 216 | gfloat xpos = spacing + xpageoffset; 217 | gfloat ypos = ICON_SPACING; 218 | gfloat oxpos = xpos; 219 | 220 | for (i = 0; i < count; i++) { 221 | oxpos = xpos; 222 | 223 | gint nrow = (ypos - ICON_SPACING) / 88; 224 | gint irow = (item_y - ICON_SPACING) / 88; 225 | 226 | oxpos += nrow*stage_area.x2; 227 | gfloat ixpos = item_x + irow*stage_area.x2; 228 | 229 | /* if required, add spacing */ 230 | if (!move_left) 231 | oxpos += spacing; 232 | 233 | if (ixpos < oxpos + 75) { 234 | newpos = i; 235 | break; 236 | } 237 | 238 | if (((i + 1) % icons_per_row) == 0) { 239 | xpos = spacing + xpageoffset; 240 | if (ypos + 88.0 < sb_area.y2 - sb_area.y1) { 241 | ypos += 88.0; 242 | } 243 | } else { 244 | xpos += 75; 245 | xpos += spacing; 246 | } 247 | } 248 | 249 | debug_printf("%s: newpos:%d\n", __func__, newpos); 250 | 251 | /* do we have a full page? */ 252 | if ((count >= MAX_PAGE_ITEMS) && (icons_per_row == (gint)device_info->home_screen_icon_columns)) { 253 | debug_printf("%s: full page detected\n", __func__); 254 | /* remove overlapping item from current page */ 255 | SBItem *last_item = g_list_nth_data(iconlist, MAX_PAGE_ITEMS-1); 256 | iconlist = g_list_remove(iconlist, last_item); 257 | /* animate it to new position */ 258 | ClutterActor *actor = clutter_actor_get_parent(last_item->texture); 259 | clutter_actor_animate(actor, CLUTTER_EASE_OUT_QUAD, 250, "x", ICON_SPACING + PAGE_X_OFFSET(pageindex + 1), "y", ICON_SPACING, NULL); 260 | /* first, we need to get the pages that we have to manipulate */ 261 | gint page_count = g_list_length(sbpages); 262 | gint last_index = pageindex; 263 | for (i = pageindex; i < page_count; i++) { 264 | GList *thepage = g_list_nth_data(sbpages, i); 265 | if (g_list_length(thepage) < (device_info->home_screen_icon_columns*device_info->home_screen_icon_rows)) { 266 | last_index = i; 267 | break; 268 | } 269 | } 270 | if ((gint)g_list_length(g_list_nth_data(sbpages, last_index)) >= MAX_PAGE_ITEMS) { 271 | /* it's the last page that is full, so we need to add a new page */ 272 | debug_printf("last page is full, appending page\n"); 273 | sbpages = g_list_append(sbpages, NULL); 274 | last_index++; 275 | } 276 | debug_printf("will alter pages %d to %d (%d pages)\n", pageindex, last_index, (last_index - pageindex) + 1); 277 | /* now manipulate the lists in reverse order */ 278 | for (i = last_index; i >= pageindex; i--) { 279 | GList *thepage = g_list_nth_data(sbpages, i); 280 | sbpages = g_list_remove(sbpages, thepage); 281 | GList *prevpage = NULL; 282 | if (i > pageindex) { 283 | prevpage = g_list_nth_data(sbpages, i-1); 284 | } 285 | gint thepage_count = g_list_length(thepage); 286 | while (thepage_count >= MAX_PAGE_ITEMS) { 287 | thepage = g_list_remove(thepage, g_list_nth_data(thepage, thepage_count-1)); 288 | thepage_count = g_list_length(thepage); 289 | } 290 | if (prevpage) { 291 | SBItem *prev_page_item = g_list_nth_data(prevpage, MAX_PAGE_ITEMS-1); 292 | /* animate this item to fix drawing error */ 293 | actor = clutter_actor_get_parent(prev_page_item->texture); 294 | clutter_actor_animate(actor, CLUTTER_LINEAR, 100, "x", ICON_SPACING + PAGE_X_OFFSET(i + 1), "y", ICON_SPACING, NULL); 295 | thepage = g_list_prepend(thepage, prev_page_item); 296 | } else { 297 | thepage = g_list_prepend(thepage, last_item); 298 | } 299 | sbpages = g_list_insert(sbpages, thepage, i); 300 | } 301 | } 302 | return g_list_insert(iconlist, newitem, newpos >= MAX_PAGE_ITEMS ? 15:newpos); 303 | } 304 | 305 | /* clock */ 306 | static void clock_set_time(ClutterActor *label, time_t t) 307 | { 308 | struct tm *curtime = localtime(&t); 309 | gchar *ctext = g_strdup_printf("%02d:%02d", curtime->tm_hour, curtime->tm_min); 310 | clutter_text_set_text(CLUTTER_TEXT(label), ctext); 311 | clutter_actor_set_position(label, (clutter_actor_get_width(stage) - clutter_actor_get_width(label)) / 2, 2); 312 | g_free(ctext); 313 | } 314 | 315 | static void clock_update_cb(ClutterTimeline *timeline, gint msecs, gpointer data) 316 | { 317 | clock_set_time(clock_label, time(NULL)); 318 | } 319 | 320 | /* gui */ 321 | static void gui_fade_init() 322 | { 323 | ClutterColor fade_color = { 0x00, 0x00, 0x00, 0xff }; 324 | fade_rectangle = clutter_rectangle_new_with_color(&fade_color); 325 | clutter_container_add_actor (CLUTTER_CONTAINER (stage), fade_rectangle); 326 | clutter_actor_set_position(fade_rectangle, 0, 0); 327 | clutter_actor_set_size(fade_rectangle, stage_area.x2, stage_area.y2); 328 | clutter_actor_set_opacity(fade_rectangle, 0); 329 | } 330 | 331 | static void gui_fade_stop() 332 | { 333 | clutter_actor_raise_top(fade_rectangle); 334 | clutter_actor_animate(CLUTTER_ACTOR(fade_rectangle), CLUTTER_EASE_OUT_QUAD, 500, "opacity", 0, NULL); 335 | clutter_actor_set_reactive(fade_rectangle, FALSE); 336 | } 337 | 338 | static void gui_fade_start() 339 | { 340 | clutter_actor_set_reactive(fade_rectangle, TRUE); 341 | clutter_actor_raise_top(fade_rectangle); 342 | clutter_actor_animate(CLUTTER_ACTOR(fade_rectangle), CLUTTER_EASE_OUT_QUAD, 500, "opacity", 180, NULL); 343 | } 344 | 345 | static gboolean spinner_spin_cb(gpointer data) 346 | { 347 | int i; 348 | for (i = 0; i < 12; i++) { 349 | ClutterActor *actor = clutter_group_get_nth_child(CLUTTER_GROUP(spinner), i); 350 | clutter_actor_set_opacity(actor, clutter_actor_get_opacity(actor)-30); 351 | } 352 | return TRUE; 353 | } 354 | 355 | static void gui_spinner_init() 356 | { 357 | ClutterActor *spinner_element = clutter_rectangle_new_with_color(&spinner_color); 358 | clutter_actor_set_size(spinner_element, 2.0, 8.0); 359 | clutter_actor_hide(spinner_element); 360 | clutter_group_add(CLUTTER_GROUP(stage), spinner_element); 361 | 362 | spinner = clutter_group_new(); 363 | int i; 364 | for (i = 0; i < 12; i++) { 365 | ClutterActor *actor = clutter_clone_new(spinner_element); 366 | clutter_group_add(CLUTTER_GROUP(spinner), actor); 367 | clutter_actor_set_position(actor, ICON_SPACING, 0.0); 368 | clutter_actor_set_opacity(actor, (guint8)(((gfloat)(i)/12.0)*255)); 369 | clutter_actor_set_rotation(actor, CLUTTER_Z_AXIS, i*30, 1.0, 15.0, 0); 370 | clutter_actor_show(actor); 371 | } 372 | clutter_actor_hide(spinner); 373 | clutter_group_add(CLUTTER_GROUP(stage), spinner); 374 | clutter_actor_set_position(spinner, (stage_area.x2-32.0)/2, (stage_area.y2-64.0)/2); 375 | spinner_timeline = clutter_timeline_new(100); 376 | clutter_timeline_set_loop(spinner_timeline, TRUE); 377 | g_signal_connect(spinner_timeline, "completed", G_CALLBACK(spinner_spin_cb), NULL); 378 | } 379 | 380 | static void gui_spinner_start() 381 | { 382 | clutter_actor_show(spinner); 383 | clutter_actor_raise_top(spinner); 384 | clutter_timeline_start(spinner_timeline); 385 | } 386 | 387 | static void gui_spinner_stop() 388 | { 389 | clutter_timeline_stop(spinner_timeline); 390 | clutter_actor_hide(spinner); 391 | } 392 | 393 | static void gui_dock_align_icons(gboolean animated) 394 | { 395 | if (!dockitems) 396 | return; 397 | gint count = g_list_length(dockitems); 398 | if (count == 0) { 399 | return; 400 | } 401 | gfloat spacing = ICON_SPACING; 402 | gfloat ypos = ICON_SPACING/2; 403 | gfloat xpos = 0.0; 404 | gint i = 0; 405 | if (count > (gint)device_info->home_screen_icon_columns) { 406 | spacing = 3.0; 407 | } 408 | gfloat totalwidth = count * device_info->home_screen_icon_width + spacing * (count - 1); 409 | xpos = (stage_area.x2 - totalwidth) / 2.0; 410 | 411 | /* set positions */ 412 | for (i = 0; i < count; i++) { 413 | SBItem *item = g_list_nth_data(dockitems, i); 414 | if (!item || !item->texture) { 415 | continue; 416 | } 417 | ClutterActor *icon = clutter_actor_get_parent(item->texture); 418 | if (!icon) { 419 | continue; 420 | } 421 | 422 | if (item != selected_item) { 423 | if (animated) { 424 | clutter_actor_animate(icon, CLUTTER_EASE_OUT_QUAD, ICON_MOVEMENT_DURATION, "x", xpos, "y", ypos, NULL); 425 | } else { 426 | clutter_actor_set_position(icon, xpos, ypos); 427 | } 428 | } 429 | 430 | xpos += device_info->home_screen_icon_width; 431 | if (i < count - 1) { 432 | xpos += spacing; 433 | } 434 | } 435 | } 436 | 437 | static void gui_page_align_icons(guint page_num, gboolean animated) 438 | { 439 | if (!sbpages) 440 | return; 441 | 442 | if (g_list_length(sbpages) == 0) { 443 | printf("%s: no pages? that's strange...\n", __func__); 444 | return; 445 | } 446 | 447 | GList *pageitems = g_list_nth_data(sbpages, page_num); 448 | if (!pageitems) { 449 | printf("%s: no items on page %d\n", __func__, page_num); 450 | return; 451 | } 452 | 453 | gint count = g_list_length(pageitems); 454 | 455 | gfloat ypos = ICON_SPACING; 456 | gfloat xpos = ICON_SPACING + PAGE_X_OFFSET(page_num); 457 | 458 | gint i = 0; 459 | gfloat item_offset = (device_info->home_screen_icon_height+ICON_SPACING); 460 | 461 | /* set positions */ 462 | for (i = 0; i < count; i++) { 463 | SBItem *item = g_list_nth_data(pageitems, i); 464 | if (!item) { 465 | debug_printf("%s: item is null for i=%d\n", __func__, i); 466 | continue; 467 | } 468 | if (!item->texture) { 469 | debug_printf("%s(%d,%d): i=%d item->texture is null\n", __func__, page_num, animated, i); 470 | continue; 471 | } 472 | ClutterActor *icon = clutter_actor_get_parent(item->texture); 473 | if (!icon) { 474 | continue; 475 | } 476 | 477 | if (item != selected_item) { 478 | if (animated) { 479 | clutter_actor_animate(icon, CLUTTER_EASE_OUT_QUAD, ICON_MOVEMENT_DURATION, "x", xpos, "y", ypos, NULL); 480 | } else { 481 | clutter_actor_set_position(icon, xpos, ypos); 482 | } 483 | } 484 | 485 | if (((i + 1) % device_info->home_screen_icon_columns) == 0) { 486 | xpos = ICON_SPACING + PAGE_X_OFFSET(page_num); 487 | if (ypos + item_offset < sb_area.y2 - sb_area.y1) { 488 | ypos += (device_info->home_screen_icon_height + ICON_SPACING); 489 | } 490 | } else { 491 | xpos += device_info->home_screen_icon_width + (stage_area.x2 - (ICON_SPACING*2) - (device_info->home_screen_icon_columns*device_info->home_screen_icon_width)) / (device_info->home_screen_icon_columns-1); 492 | } 493 | } 494 | } 495 | 496 | static void gui_page_indicator_group_align() 497 | { 498 | gint count = clutter_group_get_n_children(CLUTTER_GROUP(page_indicator_group)); 499 | gint i; 500 | gfloat xpos = 0.0; 501 | 502 | if (count <= 0) 503 | return; 504 | 505 | for (i = 0; i < count; i++) { 506 | ClutterActor *dot = clutter_group_get_nth_child(CLUTTER_GROUP(page_indicator_group), i); 507 | clutter_actor_set_position(dot, xpos, 0.0); 508 | clutter_actor_set_name(dot, g_strdup_printf("%d", i)); 509 | if (i == current_page) { 510 | clutter_actor_set_opacity(dot, 200); 511 | } else { 512 | clutter_actor_set_opacity(dot, 100); 513 | } 514 | xpos += clutter_actor_get_width(dot); 515 | } 516 | 517 | clutter_actor_set_x(page_indicator_group, (stage_area.x2 - xpos) / 2.0); 518 | } 519 | 520 | static gboolean page_indicator_clicked_cb(ClutterActor *actor, ClutterButtonEvent *event, gpointer data); 521 | 522 | static void gui_page_indicator_group_add(GList *page, int page_index) 523 | { 524 | debug_printf("%s: adding page indicator for page %d\n", __func__, page_index); 525 | if (page_indicator) { 526 | ClutterActor *actor = clutter_clone_new(page_indicator); 527 | clutter_actor_unparent(actor); 528 | clutter_actor_set_reactive(actor, TRUE); 529 | g_signal_connect(actor, 530 | "button-press-event", 531 | G_CALLBACK(page_indicator_clicked_cb), NULL); 532 | clutter_container_add_actor(CLUTTER_CONTAINER(page_indicator_group), actor); 533 | gui_page_indicator_group_align(); 534 | } 535 | } 536 | 537 | static void gui_page_indicator_group_remove(GList *page, int page_index) 538 | { 539 | debug_printf("%s: removing page indicator for page %d\n", __func__, page_index); 540 | if (page_indicator) { 541 | ClutterActor *actor = clutter_group_get_nth_child(CLUTTER_GROUP(page_indicator_group), page_index); 542 | /* afaik, this also removes it from the container */ 543 | clutter_actor_destroy(actor); 544 | gui_page_indicator_group_align(); 545 | } 546 | } 547 | 548 | static void gui_pages_remove_empty() 549 | { 550 | gint count = g_list_length(sbpages); 551 | gint i; 552 | GList *page = NULL; 553 | 554 | for (i = 0; i < count; i++) { 555 | page = g_list_nth_data(sbpages, i); 556 | debug_printf("%s: checking page %d itemcount %d\n", __func__, i, g_list_length(page)); 557 | if (g_list_length(page) == 0) { 558 | debug_printf("%s: removing page %d\n", __func__, i); 559 | gui_page_indicator_group_remove(page, i); 560 | } 561 | } 562 | sbpages = g_list_remove_all(sbpages, NULL); 563 | } 564 | 565 | static void gui_set_current_page(int pageindex, gboolean animated) 566 | { 567 | gint count = clutter_group_get_n_children(CLUTTER_GROUP(page_indicator_group)); 568 | 569 | if ((pageindex < 0) || (pageindex >= count)) 570 | return; 571 | 572 | /* make sure the page has correct aligned icons */ 573 | gui_page_align_icons(pageindex, FALSE); 574 | 575 | current_page = pageindex; 576 | 577 | gui_page_indicator_group_align(); 578 | 579 | if (animated) { 580 | clutter_actor_animate(the_sb, CLUTTER_EASE_IN_OUT_CUBIC, 400, "x", (gfloat) (-PAGE_X_OFFSET(current_page)), NULL); 581 | } else { 582 | clutter_actor_set_x(the_sb, (gfloat)(-PAGE_X_OFFSET(current_page))); 583 | } 584 | } 585 | 586 | static void gui_show_next_page() 587 | { 588 | gui_set_current_page(current_page+1, TRUE); 589 | } 590 | 591 | static void gui_show_previous_page() 592 | { 593 | gui_set_current_page(current_page-1, TRUE); 594 | } 595 | 596 | static plist_t sbitem_get_subitems(SBItem *item) 597 | { 598 | plist_t result = plist_new_array(); 599 | if (item && item->subitems) { 600 | guint i; 601 | for (i = 0; i < g_list_length(item->subitems); i++) { 602 | SBItem *subitem = g_list_nth_data(item->subitems, i); 603 | plist_t node = plist_dict_get_item(subitem->node, "displayIdentifier"); 604 | if (!node) { 605 | printf("could not get displayIdentifier\n"); 606 | continue; 607 | } 608 | plist_array_append_item(result, plist_copy(node)); 609 | } 610 | } 611 | return result; 612 | } 613 | 614 | static plist_t sbitem_to_plist(SBItem *item) 615 | { 616 | plist_t result = plist_new_dict(); 617 | if (!item) { 618 | return result; 619 | } 620 | plist_t node; 621 | if (item->is_folder) { 622 | node = plist_dict_get_item(item->node, "displayName"); 623 | if (!node) { 624 | printf("could not get displayName for folder!\n"); 625 | return result; 626 | } 627 | plist_dict_insert_item(result, "displayName", plist_copy(node)); 628 | plist_t iconlists = plist_new_array(); 629 | plist_array_append_item(iconlists, sbitem_get_subitems(item)); 630 | plist_dict_insert_item(result, "iconLists", iconlists); 631 | } else { 632 | node = plist_dict_get_item(item->node, "displayIdentifier"); 633 | if (!node) { 634 | printf("could not get displayIdentifier\n"); 635 | return result; 636 | } 637 | plist_dict_insert_item(result, "displayIdentifier", plist_copy(node)); 638 | } 639 | return result; 640 | } 641 | 642 | plist_t gui_get_iconstate(const char *format_version) 643 | { 644 | plist_t iconstate = NULL; 645 | plist_t pdockarray = NULL; 646 | plist_t pdockitems = NULL; 647 | guint i; 648 | 649 | int use_version = 1; 650 | if (format_version && (strcmp(format_version, "2") == 0)) { 651 | use_version = 2; 652 | } 653 | 654 | guint count = g_list_length(dockitems); 655 | pdockitems = plist_new_array(); 656 | for (i = 0; i < count; i++) { 657 | SBItem *item = g_list_nth_data(dockitems, i); 658 | if (item && item->node) { 659 | plist_array_append_item(pdockitems, sbitem_to_plist(item)); 660 | } 661 | } 662 | 663 | if (use_version == 1) { 664 | for (i = count; i < num_dock_items; i++) { 665 | plist_array_append_item(pdockitems, plist_new_bool(0)); 666 | } 667 | } 668 | pdockarray = plist_new_array(); 669 | plist_array_append_item(pdockarray, pdockitems); 670 | 671 | iconstate = plist_new_array(); 672 | plist_array_append_item(iconstate, pdockarray); 673 | 674 | for (i = 0; i < g_list_length(sbpages); i++) { 675 | GList *page = g_list_nth_data(sbpages, i); 676 | if (page) { 677 | guint j; 678 | count = g_list_length(page); 679 | if (count <= 0) { 680 | continue; 681 | } 682 | plist_t ppage = plist_new_array(); 683 | plist_t row = NULL; 684 | if (use_version == 2) { 685 | row = plist_new_array(); 686 | plist_array_append_item(ppage, row); 687 | } 688 | for (j = 0; j < (device_info->home_screen_icon_columns*device_info->home_screen_icon_rows); j++) { 689 | SBItem *item = g_list_nth_data(page, j); 690 | if (use_version == 1) { 691 | if ((j % device_info->home_screen_icon_columns) == 0) { 692 | row = plist_new_array(); 693 | plist_array_append_item(ppage, row); 694 | } 695 | } 696 | if (item && item->node) { 697 | plist_array_append_item(row, sbitem_to_plist(item)); 698 | } else { 699 | if (use_version == 1) 700 | plist_array_append_item(row, plist_new_bool(0)); 701 | } 702 | } 703 | plist_array_append_item(iconstate, plist_copy(ppage)); 704 | plist_free(ppage); 705 | } 706 | } 707 | 708 | return iconstate; 709 | } 710 | 711 | /* input */ 712 | static gboolean stage_motion_cb(ClutterActor *actor, ClutterMotionEvent *event, gpointer user_data) 713 | { 714 | /* check if an item has been raised */ 715 | if (!selected_item) { 716 | return FALSE; 717 | } 718 | 719 | ClutterActor *icon = clutter_actor_get_parent(selected_item->texture); 720 | 721 | clutter_actor_move_by(icon, (event->x - start_x), (event->y - start_y)); 722 | 723 | if (event->x-start_x > 0) { 724 | move_left = FALSE; 725 | } else { 726 | move_left = TRUE; 727 | } 728 | 729 | start_x = event->x; 730 | start_y = event->y; 731 | 732 | gfloat center_x; 733 | gfloat center_y; 734 | clutter_actor_get_abs_center(icon, ¢er_x, ¢er_y); 735 | 736 | if (!selected_folder && clutter_actor_box_contains(&left_trigger, center_x - (device_info->home_screen_icon_width / 2), center_y)) { 737 | if (current_page > 0) { 738 | if (elapsed_ms(&last_page_switch, 1000)) { 739 | gui_show_previous_page(); 740 | gettimeofday(&last_page_switch, NULL); 741 | } 742 | } 743 | } else if (!selected_folder && clutter_actor_box_contains(&right_trigger, center_x + (device_info->home_screen_icon_width / 2), center_y)) { 744 | if (current_page < (gint)(g_list_length(sbpages)-1)) { 745 | if (elapsed_ms(&last_page_switch, 1000)) { 746 | gui_show_next_page(); 747 | gettimeofday(&last_page_switch, NULL); 748 | } 749 | } 750 | } 751 | 752 | if (selected_folder) { 753 | selected_folder->subitems = g_list_remove(selected_folder->subitems, selected_item); 754 | selected_folder->subitems = 755 | iconlist_insert_item_at(selected_folder->subitems, selected_item, (center_x - 0.0), (center_y - split_pos - clutter_actor_get_y(aniupper)), 0, 4); 756 | gui_folder_align_icons(selected_folder, TRUE); 757 | } else if (selected_item->is_dock_item) { 758 | dockitems = g_list_remove(dockitems, selected_item); 759 | if (center_y >= dock_area.y1) { 760 | debug_printf("%s: icon from dock moving inside the dock!\n", __func__); 761 | selected_item->is_dock_item = TRUE; 762 | dockitems = 763 | iconlist_insert_item_at(dockitems, selected_item, (center_x - dock_area.x1), (center_y - dock_area.y1), 0, num_dock_items); 764 | gui_dock_align_icons(TRUE); 765 | } else { 766 | debug_printf("%s: icon from dock moving outside the dock!\n", __func__); 767 | selected_item->is_dock_item = FALSE; 768 | gui_page_align_icons(current_page, TRUE); 769 | } 770 | } else { 771 | int p = current_page; 772 | int i; 773 | GList *pageitems = NULL; 774 | debug_printf("%s: current_page %d\n", __func__, p); 775 | /* remove selected_item from all pages */ 776 | int count = g_list_length(sbpages); 777 | for (i = 0; i < count; i++) { 778 | pageitems = g_list_nth_data(sbpages, i); 779 | sbpages = g_list_remove(sbpages, pageitems); 780 | pageitems = g_list_remove(pageitems, selected_item); 781 | sbpages = g_list_insert(sbpages, pageitems, i); 782 | } 783 | /* get current page */ 784 | pageitems = g_list_nth_data(sbpages, p); 785 | /* remove current page from pages list as we will alter it */ 786 | sbpages = g_list_remove(sbpages, pageitems); 787 | if (center_y >= dock_area.y1 && (g_list_length(dockitems) < num_dock_items)) { 788 | debug_printf("%s: regular icon is moving inside the dock!\n", __func__); 789 | selected_item->is_dock_item = TRUE; 790 | } else { 791 | debug_printf("%s: regular icon is moving!\n", __func__); 792 | pageitems = 793 | iconlist_insert_item_at(pageitems, selected_item, (center_x - sb_area.x1) + PAGE_X_OFFSET(p), (center_y - sb_area.y1), p, 4); 794 | } 795 | /* insert back current page */ 796 | sbpages = g_list_insert(sbpages, pageitems, p); 797 | gui_dock_align_icons(TRUE); 798 | gui_page_align_icons(p, TRUE); 799 | } 800 | 801 | return TRUE; 802 | } 803 | 804 | static gboolean page_indicator_clicked_cb(ClutterActor *actor, ClutterButtonEvent *event, gpointer data) 805 | { 806 | if (event->click_count > 1) { 807 | return FALSE; 808 | } 809 | const gchar *index_str = clutter_actor_get_name(actor); 810 | int pageindex = strtol(index_str, NULL, 10); 811 | debug_printf("page indicator for page %d has been clicked\n", pageindex); 812 | gui_set_current_page(pageindex, TRUE); 813 | return TRUE; 814 | } 815 | 816 | static void gui_folder_redraw_subitems(SBItem *item) 817 | { 818 | if (!item) 819 | return; 820 | 821 | ClutterActor *minigrp = NULL; 822 | ClutterActor *grp = clutter_actor_get_parent(item->texture); 823 | guint cnt = clutter_group_get_n_children(CLUTTER_GROUP(grp)); 824 | guint i; 825 | for (i = 0; i < cnt; i++) { 826 | ClutterActor *act = clutter_group_get_nth_child(CLUTTER_GROUP(grp), i); 827 | const char *nm = clutter_actor_get_name(act); 828 | if (nm && !strcmp(nm, "mini")) { 829 | minigrp = act; 830 | break; 831 | } 832 | } 833 | if (minigrp) { 834 | clutter_actor_destroy(minigrp); 835 | } 836 | 837 | minigrp = clutter_group_new(); 838 | clutter_actor_set_name(minigrp, "mini"); 839 | clutter_container_add_actor(CLUTTER_CONTAINER(grp), minigrp); 840 | for (i = 0; i < g_list_length(item->subitems); i++) { 841 | SBItem *subitem = (SBItem*)g_list_nth_data(item->subitems, i); 842 | if (subitem && subitem->texture && subitem->node) { 843 | ClutterActor *suba = clutter_clone_new(subitem->texture); 844 | clutter_actor_unparent(suba); 845 | clutter_container_add_actor(CLUTTER_CONTAINER(minigrp), suba); 846 | clutter_actor_set_scale(suba, 0.22, 0.22); 847 | clutter_actor_set_position(suba, 8.0 + (i%3)*ICON_SPACING, 8.0 + ((double)(int)((int)i/(int)3))*ICON_SPACING); 848 | if (i < 9) 849 | clutter_actor_show(suba); 850 | else 851 | clutter_actor_hide(suba); 852 | } 853 | } 854 | } 855 | 856 | static void gui_folder_align_icons(SBItem *item, gboolean animated) 857 | { 858 | if (!item || !item->subitems) 859 | return; 860 | 861 | gint count = g_list_length(item->subitems); 862 | 863 | gfloat ypos = 8.0 + ICON_SPACING + ICON_SPACING; 864 | gfloat xpos = (ICON_SPACING / 2); 865 | gint i = 0; 866 | 867 | /* set positions */ 868 | for (i = 0; i < count; i++) { 869 | SBItem *si = g_list_nth_data(item->subitems, i); 870 | if (!si) { 871 | debug_printf("%s: item is null for i=%d\n", __func__, i); 872 | continue; 873 | } 874 | if (!si->texture) { 875 | debug_printf("%s: i=%d item->texture is null\n", __func__, i); 876 | continue; 877 | } 878 | ClutterActor *icon = clutter_actor_get_parent(si->texture); 879 | if (!icon) { 880 | continue; 881 | } 882 | 883 | if (si != selected_item) { 884 | if (animated) { 885 | clutter_actor_animate(icon, CLUTTER_EASE_OUT_QUAD, 250, "x", xpos, "y", ypos, NULL); 886 | } else { 887 | clutter_actor_set_position(icon, xpos, ypos); 888 | } 889 | } 890 | 891 | if (((i + 1) % 4) == 0) { 892 | xpos = ICON_SPACING; 893 | ypos += 88.0; 894 | } else { 895 | xpos += 76.0; 896 | } 897 | } 898 | } 899 | 900 | static gboolean folderview_close_finish(gpointer user_data) 901 | { 902 | SBItem *item = (SBItem*)user_data; 903 | 904 | ClutterActor *label = clutter_group_get_nth_child(CLUTTER_GROUP(folder), 2); 905 | 906 | const gchar *oldname = clutter_text_get_text(CLUTTER_TEXT(item->label)); 907 | const gchar *newname = clutter_text_get_text(CLUTTER_TEXT(label)); 908 | if (g_str_equal(oldname, newname) == FALSE) { 909 | gfloat oldwidth = clutter_actor_get_width(item->label); 910 | clutter_text_set_text(CLUTTER_TEXT(item->label), newname); 911 | plist_dict_remove_item(item->node, "displayName"); 912 | plist_dict_insert_item(item->node, "displayName", plist_new_string(newname)); 913 | gfloat newwidth = clutter_actor_get_width(item->label); 914 | gfloat xshift = -(newwidth-oldwidth)/2; 915 | clutter_actor_move_by(item->label, xshift, 0); 916 | if (item->label_shadow) { 917 | clutter_text_set_text(CLUTTER_TEXT(item->label_shadow), newname); 918 | clutter_actor_move_by(item->label_shadow, xshift, 0); 919 | } 920 | } 921 | clutter_actor_show(item->label); 922 | if (item->label_shadow) { 923 | clutter_actor_show(item->label_shadow); 924 | } 925 | 926 | ClutterActor *newparent = clutter_actor_get_parent(item->texture); 927 | GList *subitems = item->subitems; 928 | guint i; 929 | for (i = 0; i < g_list_length(subitems); i++) { 930 | SBItem *si = g_list_nth_data(subitems, i); 931 | ClutterActor *actor = clutter_actor_get_parent(si->texture); 932 | clutter_actor_reparent(actor, newparent); 933 | clutter_actor_hide(actor); 934 | } 935 | 936 | gui_folder_redraw_subitems(item); 937 | 938 | clutter_actor_destroy(folder); 939 | folder = NULL; 940 | clutter_actor_destroy(aniupper); 941 | aniupper = NULL; 942 | clutter_actor_destroy(anilower); 943 | anilower = NULL; 944 | split_pos = 0.0; 945 | 946 | /* un-dim sb and dock items */ 947 | GList *page = g_list_nth_data(sbpages, current_page); 948 | SBItem *it; 949 | ClutterActor *act; 950 | for (i = 0; i < g_list_length(page); i++) { 951 | it = g_list_nth_data(page, i); 952 | act = clutter_actor_get_parent(it->texture); 953 | clutter_actor_set_opacity(act, 255); 954 | } 955 | for (i = 0; i < g_list_length(dockitems); i++) { 956 | it = g_list_nth_data(dockitems, i); 957 | act = clutter_actor_get_parent(it->texture); 958 | clutter_actor_set_opacity(act, 255); 959 | } 960 | 961 | /* show page indicators */ 962 | clutter_actor_show(page_indicator_group); 963 | 964 | clutter_actor_set_reactive(item->texture, TRUE); 965 | 966 | selected_folder = NULL; 967 | 968 | return FALSE; 969 | } 970 | 971 | static void folderview_close(SBItem *folderitem) 972 | { 973 | clutter_actor_set_reactive(folderitem->texture, FALSE); 974 | 975 | clutter_actor_set_reactive(aniupper, FALSE); 976 | clutter_actor_set_reactive(anilower, FALSE); 977 | 978 | clutter_actor_raise_top(aniupper); 979 | clutter_actor_raise_top(anilower); 980 | clutter_actor_animate(aniupper, CLUTTER_EASE_IN_OUT_QUAD, FOLDER_ANIM_DURATION, "y", 0.0, NULL); 981 | clutter_actor_animate(anilower, CLUTTER_EASE_IN_OUT_QUAD, FOLDER_ANIM_DURATION, "y", 0.0, NULL); 982 | clutter_actor_animate(folder, CLUTTER_EASE_IN_OUT_QUAD, FOLDER_ANIM_DURATION, "y", split_pos, NULL); 983 | 984 | clutter_threads_add_timeout(FOLDER_ANIM_DURATION, (GSourceFunc)folderview_close_finish, (gpointer)folderitem); 985 | } 986 | 987 | static gboolean folderview_close_cb(ClutterActor *actor, ClutterButtonEvent *event, gpointer user_data) 988 | { 989 | /* discard double clicks */ 990 | if (event->click_count > 1) { 991 | return FALSE; 992 | } 993 | 994 | SBItem *item = (SBItem*)user_data; 995 | 996 | folderview_close(item); 997 | 998 | return TRUE; 999 | } 1000 | 1001 | static gboolean folderview_open_finish(gpointer user_data) 1002 | { 1003 | ClutterActor *marker = clutter_group_get_nth_child(CLUTTER_GROUP(folder), 2); 1004 | 1005 | clutter_actor_raise_top(folder); 1006 | clutter_actor_show(marker); 1007 | 1008 | g_signal_connect(aniupper, "button-press-event", G_CALLBACK(folderview_close_cb), user_data); 1009 | g_signal_connect(anilower, "button-press-event", G_CALLBACK(folderview_close_cb), user_data); 1010 | 1011 | return FALSE; 1012 | } 1013 | 1014 | static void folderview_open(SBItem *item) 1015 | { 1016 | GList *page = g_list_nth_data(sbpages, current_page); 1017 | guint i; 1018 | SBItem *it; 1019 | ClutterActor *act; 1020 | gfloat ypos = 0; 1021 | gfloat xpos = 0; 1022 | 1023 | gboolean is_dock_folder = FALSE; 1024 | 1025 | selected_folder = item; 1026 | 1027 | ClutterActor *fldr = NULL; 1028 | 1029 | /* dim the springboard icons */ 1030 | for (i = 0; i < g_list_length(page); i++) { 1031 | it = g_list_nth_data(page, i); 1032 | act = clutter_actor_get_parent(it->texture); 1033 | if (item == it) { 1034 | clutter_actor_set_opacity(act, 255); 1035 | ypos = 24.0+(gfloat)((int)(i / 4)+1) * 88.0; 1036 | xpos = 16 + ((i % 4))*76.0; 1037 | clutter_actor_hide(it->label); 1038 | if (it->label_shadow) { 1039 | clutter_actor_hide(it->label_shadow); 1040 | } 1041 | fldr = act; 1042 | } else { 1043 | clutter_actor_set_opacity(act, 64); 1044 | } 1045 | } 1046 | 1047 | /* dim the dock icons */ 1048 | guint count = g_list_length(dockitems); 1049 | for (i = 0; i < count; i++) { 1050 | it = g_list_nth_data(dockitems, i); 1051 | act = clutter_actor_get_parent(it->texture); 1052 | if (item == it) { 1053 | clutter_actor_set_opacity(act, 255); 1054 | ypos = stage_area.y1 - DOCK_HEIGHT - ICON_SPACING; 1055 | gfloat spacing = ICON_SPACING; 1056 | if (count > 4) { 1057 | spacing = 3.0; 1058 | } 1059 | gfloat totalwidth = count*57.0 + (count-1) * spacing; 1060 | xpos = (stage_area.x2 - totalwidth)/2.0 + (i*57.0) + (i*spacing); 1061 | clutter_actor_hide(it->label); 1062 | if (it->label_shadow) { 1063 | clutter_actor_hide(it->label_shadow); 1064 | } 1065 | is_dock_folder = TRUE; 1066 | fldr = act; 1067 | } else { 1068 | clutter_actor_set_opacity(act, 64); 1069 | } 1070 | } 1071 | 1072 | /* hide page indicators */ 1073 | clutter_actor_hide(page_indicator_group); 1074 | 1075 | if (item->texture_shadow) { 1076 | clutter_actor_hide(item->texture_shadow); 1077 | } 1078 | 1079 | /* make snapshot from the stage */ 1080 | guchar *shot = clutter_stage_read_pixels(CLUTTER_STAGE(stage), 0, 0, stage_area.x2, stage_area.y2); 1081 | if (!shot) { 1082 | printf("Error creating stage snapshot!\n"); 1083 | return; 1084 | } 1085 | 1086 | if (item->texture_shadow) { 1087 | clutter_actor_show(item->texture_shadow); 1088 | } 1089 | 1090 | /* upper */ 1091 | aniupper = clutter_group_new(); 1092 | clutter_container_add_actor(CLUTTER_CONTAINER(stage), aniupper); 1093 | act = clutter_texture_new(); 1094 | clutter_texture_set_from_rgb_data(CLUTTER_TEXTURE(act), shot, TRUE, stage_area.x2, ypos, stage_area.x2*4, 4, CLUTTER_TEXTURE_NONE, NULL); 1095 | clutter_container_add_actor(CLUTTER_CONTAINER(aniupper), act); 1096 | clutter_actor_set_position(aniupper, 0, 0); 1097 | clutter_actor_set_reactive(aniupper, TRUE); 1098 | clutter_actor_show(aniupper); 1099 | clutter_actor_raise_top(aniupper); 1100 | 1101 | /* lower */ 1102 | anilower = clutter_group_new(); 1103 | clutter_container_add_actor(CLUTTER_CONTAINER(stage), anilower); 1104 | act = clutter_texture_new(); 1105 | clutter_texture_set_from_rgb_data(CLUTTER_TEXTURE(act), shot, TRUE, stage_area.x2, stage_area.y2, stage_area.x2*4, 4, CLUTTER_TEXTURE_NONE, NULL); 1106 | clutter_actor_set_clip(act, 0.0, ypos, (gfloat)(stage_area.x2), (gfloat)(stage_area.y2)-ypos); 1107 | clutter_container_add_actor(CLUTTER_CONTAINER(anilower), act); 1108 | clutter_actor_set_position(anilower, 0, 0); 1109 | clutter_actor_set_reactive(anilower, TRUE); 1110 | clutter_actor_show(anilower); 1111 | clutter_actor_raise_top(anilower); 1112 | 1113 | /* add a clone of the original folder icon */ 1114 | act = clutter_clone_new(fldr); 1115 | if (is_dock_folder) { 1116 | clutter_container_add_actor(CLUTTER_CONTAINER(anilower), act); 1117 | clutter_actor_set_position(act, xpos, ypos+20.0); 1118 | } else { 1119 | clutter_container_add_actor(CLUTTER_CONTAINER(aniupper), act); 1120 | clutter_actor_set_position(act, xpos, ypos-80.0); 1121 | } 1122 | 1123 | /* create folder container */ 1124 | folder = clutter_group_new(); 1125 | clutter_container_add_actor(CLUTTER_CONTAINER(stage), folder); 1126 | clutter_actor_raise_top(folder); 1127 | clutter_actor_set_position(folder, 0, ypos); 1128 | clutter_actor_show(folder); 1129 | 1130 | /* folder background rect */ 1131 | ClutterColor folderbg = {0x70, 0x70, 0x70, 255}; 1132 | act = clutter_rectangle_new_with_color(&folderbg); 1133 | ClutterColor folderbd = {0xe0, 0xe0, 0xe0, 255}; 1134 | clutter_rectangle_set_border_color(CLUTTER_RECTANGLE(act), &folderbd); 1135 | clutter_rectangle_set_border_width(CLUTTER_RECTANGLE(act), 1); 1136 | clutter_actor_set_size(act, stage_area.x2, 1); 1137 | clutter_actor_set_position(act, 0, 0); 1138 | clutter_actor_set_reactive(act, TRUE); 1139 | clutter_container_add_actor(CLUTTER_CONTAINER(folder), act); 1140 | clutter_actor_show(act); 1141 | 1142 | /* create folder name label */ 1143 | ClutterColor rcolor = {255, 255, 255, 255}; 1144 | ClutterActor *trect = clutter_rectangle_new_with_color(&rcolor); 1145 | clutter_container_add_actor(CLUTTER_CONTAINER(folder), trect); 1146 | clutter_actor_set_position(trect, 16.0, 8.0); 1147 | clutter_actor_set_size(trect, (gfloat)(stage_area.x2)-32.0, 24.0); 1148 | 1149 | const gchar *ltext = clutter_text_get_text(CLUTTER_TEXT(item->label)); 1150 | ClutterColor lcolor = {0, 0, 0, 255}; 1151 | ClutterActor *lbl = clutter_text_new_full(FOLDER_LARGE_FONT, ltext, &lcolor); 1152 | clutter_container_add_actor(CLUTTER_CONTAINER(folder), lbl); 1153 | clutter_actor_set_position(lbl, 16.0, 8.0); 1154 | clutter_actor_set_width(lbl, (gfloat)(stage_area.x2)-32.0); 1155 | clutter_actor_raise(lbl, trect); 1156 | clutter_actor_grab_key_focus(lbl); 1157 | clutter_text_set_editable(CLUTTER_TEXT(lbl), TRUE); 1158 | clutter_text_set_selectable(CLUTTER_TEXT(lbl), TRUE); 1159 | clutter_text_set_single_line_mode(CLUTTER_TEXT(lbl), TRUE); 1160 | clutter_text_set_line_wrap(CLUTTER_TEXT(lbl), FALSE); 1161 | clutter_actor_set_reactive(lbl, TRUE); 1162 | ClutterColor selcolor = {0, 0, 0xa0, 200}; 1163 | ClutterColor curcolor = {0, 0, 0xa0, 255}; 1164 | clutter_text_set_selection_color(CLUTTER_TEXT(lbl), &selcolor); 1165 | clutter_text_set_cursor_color(CLUTTER_TEXT(lbl), &curcolor); 1166 | 1167 | /* calculate height */ 1168 | gfloat fh = 8.0 + 18.0 + 8.0; 1169 | if (item->subitems && (g_list_length(item->subitems) > 0)) { 1170 | fh += (((g_list_length(item->subitems)-1)/device_info->home_screen_icon_columns) + 1)*88.0; 1171 | } else { 1172 | fh += 88.0; 1173 | } 1174 | 1175 | /* folder marker */ 1176 | ClutterActor *marker = clutter_clone_new(folder_marker); 1177 | clutter_actor_unparent(marker); 1178 | clutter_container_add_actor(CLUTTER_CONTAINER(folder), marker); 1179 | if (is_dock_folder) { 1180 | clutter_actor_set_rotation(marker, CLUTTER_Z_AXIS, 180.0, 29.0, 8.0, 0.0); 1181 | clutter_actor_set_position(marker, xpos, fh-2.0); 1182 | clutter_actor_hide(marker); 1183 | } else { 1184 | clutter_actor_set_position(marker, xpos, -14.0); 1185 | clutter_actor_show(marker); 1186 | } 1187 | 1188 | /* reparent the icons to the folder */ 1189 | for (i = 0; i < g_list_length(item->subitems); i++) { 1190 | SBItem *si = g_list_nth_data(item->subitems, i); 1191 | ClutterActor *a = clutter_actor_get_parent(si->texture); 1192 | clutter_actor_reparent(a, folder); 1193 | clutter_actor_set_position(a, 0, 0); 1194 | clutter_actor_show(a); 1195 | } 1196 | 1197 | /* align folder icons */ 1198 | gui_folder_align_icons(item, FALSE); 1199 | 1200 | /* distance to move upwards */ 1201 | gfloat move_up_by = 0; 1202 | if (is_dock_folder) { 1203 | move_up_by = fh; 1204 | } else { 1205 | if ((ypos + fh) > (stage_area.y2 - DOCK_HEIGHT/2)) { 1206 | move_up_by = (ypos + fh) - (stage_area.y2 - DOCK_HEIGHT/2); 1207 | } 1208 | } 1209 | 1210 | clutter_actor_raise_top(folder); 1211 | clutter_actor_raise_top(anilower); 1212 | 1213 | /* now animate the actors */ 1214 | clutter_actor_animate(act, CLUTTER_EASE_IN_OUT_QUAD, FOLDER_ANIM_DURATION, "height", fh, NULL); 1215 | clutter_actor_animate(folder, CLUTTER_EASE_IN_OUT_QUAD, FOLDER_ANIM_DURATION, "y", ypos-move_up_by, NULL); 1216 | 1217 | clutter_actor_animate(aniupper, CLUTTER_EASE_IN_OUT_QUAD, FOLDER_ANIM_DURATION, "y", (gfloat) -move_up_by, NULL); 1218 | clutter_actor_animate(anilower, CLUTTER_EASE_IN_OUT_QUAD, FOLDER_ANIM_DURATION, "y", (gfloat) fh-move_up_by, NULL); 1219 | 1220 | free(shot); 1221 | 1222 | split_pos = ypos; 1223 | 1224 | clutter_threads_add_timeout(FOLDER_ANIM_DURATION, (GSourceFunc)folderview_open_finish, item); 1225 | } 1226 | 1227 | static gboolean item_button_press_cb(ClutterActor *actor, ClutterButtonEvent *event, gpointer user_data) 1228 | { 1229 | if (!user_data) { 1230 | return FALSE; 1231 | } 1232 | 1233 | if (selected_item) { 1234 | /* do not allow a button_press event without a prior release */ 1235 | return FALSE; 1236 | } 1237 | 1238 | /* discard double clicks */ 1239 | if (event->click_count > 2) { 1240 | return FALSE; 1241 | } 1242 | 1243 | SBItem *item = (SBItem*)user_data; 1244 | 1245 | if (event->click_count == 2) { 1246 | if (item->is_folder) { 1247 | folderview_open(item); 1248 | return TRUE; 1249 | } else { 1250 | return FALSE; 1251 | } 1252 | } 1253 | 1254 | if (!item->enabled) { 1255 | return FALSE; 1256 | } 1257 | 1258 | char *strval = sbitem_get_display_name(item); 1259 | 1260 | g_mutex_lock(selected_mutex); 1261 | debug_printf("%s: %s mouse pressed\n", __func__, strval); 1262 | 1263 | if (actor) { 1264 | gfloat diffx = 0.0; 1265 | gfloat diffy = 0.0; 1266 | ClutterActor *sc = clutter_actor_get_parent(actor); 1267 | if (item->is_dock_item) { 1268 | clutter_text_set_color(CLUTTER_TEXT(item->label), &item_text_color); 1269 | clutter_actor_set_y(item->label, clutter_actor_get_y(item->texture) + device_info->home_screen_icon_height); 1270 | if (item->label_shadow) { 1271 | clutter_actor_set_y(item->label_shadow, clutter_actor_get_y(item->texture) + device_info->home_screen_icon_height + 1.0); 1272 | } 1273 | diffx = dock_area.x1; 1274 | diffy = dock_area.y1; 1275 | } else { 1276 | diffx = sb_area.x1 - PAGE_X_OFFSET(current_page); 1277 | diffy = sb_area.y1; 1278 | } 1279 | clutter_actor_reparent(sc, stage); 1280 | clutter_actor_set_position(sc, clutter_actor_get_x(sc) + diffx, clutter_actor_get_y(sc) + diffy); 1281 | clutter_actor_raise_top(sc); 1282 | clutter_actor_set_scale_full(sc, 1.2, 1.2, 1283 | clutter_actor_get_x(actor) + 1284 | clutter_actor_get_width(actor) / 2, 1285 | clutter_actor_get_y(actor) + clutter_actor_get_height(actor) / 2); 1286 | clutter_actor_set_opacity(sc, 160); 1287 | selected_item = item; 1288 | start_x = event->x; 1289 | start_y = event->y; 1290 | } 1291 | g_mutex_unlock(selected_mutex); 1292 | 1293 | /* add pages and page indicators as needed */ 1294 | GList *page = NULL; 1295 | gui_page_indicator_group_add(page, g_list_length(sbpages)); 1296 | sbpages = g_list_append(sbpages, page); 1297 | 1298 | return TRUE; 1299 | } 1300 | 1301 | static gboolean item_button_release_cb(ClutterActor *actor, ClutterButtonEvent *event, gpointer user_data) 1302 | { 1303 | if (!user_data) { 1304 | return FALSE; 1305 | } 1306 | 1307 | /* discard double clicks */ 1308 | if (event->click_count > 1) { 1309 | return FALSE; 1310 | } 1311 | 1312 | SBItem *item = (SBItem*)user_data; 1313 | if (!item->enabled) { 1314 | return FALSE; 1315 | } 1316 | item->enabled = FALSE; 1317 | 1318 | char *strval = sbitem_get_display_name(item); 1319 | 1320 | /* remove empty pages and page indicators as needed */ 1321 | gui_pages_remove_empty(); 1322 | int count = g_list_length(sbpages); 1323 | if (current_page >= count) { 1324 | gui_set_current_page(count-1, FALSE); 1325 | } 1326 | 1327 | g_mutex_lock(selected_mutex); 1328 | debug_printf("%s: %s mouse released\n", __func__, strval); 1329 | 1330 | if (actor) { 1331 | ClutterActor *sc = clutter_actor_get_parent(actor); 1332 | clutter_actor_set_scale_full(sc, 1.0, 1.0, 1333 | clutter_actor_get_x(actor) + 1334 | clutter_actor_get_width(actor) / 2, 1335 | clutter_actor_get_y(actor) + clutter_actor_get_height(actor) / 2); 1336 | clutter_actor_set_opacity(sc, 255); 1337 | if (item->is_dock_item) { 1338 | clutter_text_set_color(CLUTTER_TEXT(item->label), &dock_item_text_color); 1339 | clutter_actor_set_y(item->label, clutter_actor_get_y(item->texture) + device_info->home_screen_icon_height); 1340 | if (item->label_shadow) { 1341 | clutter_actor_set_y(item->label_shadow, clutter_actor_get_y(item->texture) + device_info->home_screen_icon_height + 1.0); 1342 | } 1343 | clutter_actor_reparent(sc, the_dock); 1344 | clutter_actor_set_position(sc, 1345 | clutter_actor_get_x(sc) - dock_area.x1, clutter_actor_get_y(sc) - dock_area.y1); 1346 | } else { 1347 | clutter_actor_reparent(sc, the_sb); 1348 | clutter_actor_set_position(sc, 1349 | clutter_actor_get_x(sc) + 1350 | PAGE_X_OFFSET(current_page) - sb_area.x1, clutter_actor_get_y(sc) - sb_area.y1); 1351 | } 1352 | } 1353 | 1354 | selected_item = NULL; 1355 | gui_dock_align_icons(TRUE); 1356 | gui_page_align_icons(current_page, TRUE); 1357 | start_x = 0.0; 1358 | start_y = 0.0; 1359 | 1360 | clutter_threads_add_timeout(ICON_MOVEMENT_DURATION, (GSourceFunc)item_enable, (gpointer)item); 1361 | 1362 | g_mutex_unlock(selected_mutex); 1363 | 1364 | return TRUE; 1365 | } 1366 | 1367 | static gboolean stage_key_press_cb(ClutterActor *actor, ClutterEvent *event, gpointer user_data) 1368 | { 1369 | if (!user_data || (event->type != CLUTTER_KEY_PRESS)) { 1370 | return FALSE; 1371 | } 1372 | 1373 | guint symbol = clutter_event_get_key_symbol(event); 1374 | switch(symbol) { 1375 | case CLUTTER_Right: 1376 | gui_show_next_page(); 1377 | break; 1378 | case CLUTTER_Left: 1379 | gui_show_previous_page(); 1380 | break; 1381 | default: 1382 | return FALSE; 1383 | } 1384 | return TRUE; 1385 | } 1386 | 1387 | static gboolean subitem_button_press_cb(ClutterActor *actor, ClutterButtonEvent *event, gpointer user_data) 1388 | { 1389 | if (!user_data) { 1390 | return FALSE; 1391 | } 1392 | 1393 | if (selected_item) { 1394 | /* do not allow a button_press event without a prior release */ 1395 | return FALSE; 1396 | } 1397 | 1398 | /* discard double clicks */ 1399 | if (event->click_count > 1) { 1400 | return FALSE; 1401 | } 1402 | 1403 | SBItem *item = (SBItem*)user_data; 1404 | if (!item->enabled) { 1405 | return FALSE; 1406 | } 1407 | 1408 | char *strval = sbitem_get_display_name(item); 1409 | 1410 | g_mutex_lock(selected_mutex); 1411 | debug_printf("%s: %s mouse pressed\n", __func__, strval); 1412 | 1413 | if (actor) { 1414 | gfloat diffx = 0.0; 1415 | gfloat diffy = 0.0; 1416 | ClutterActor *sc = clutter_actor_get_parent(actor); 1417 | 1418 | diffy = split_pos + clutter_actor_get_y(aniupper); 1419 | 1420 | clutter_actor_reparent(sc, stage); 1421 | clutter_actor_set_position(sc, clutter_actor_get_x(sc) + diffx, clutter_actor_get_y(sc) + diffy); 1422 | clutter_actor_raise_top(sc); 1423 | clutter_actor_set_scale_full(sc, 1.2, 1.2, 1424 | clutter_actor_get_x(actor) + 1425 | clutter_actor_get_width(actor) / 2, 1426 | clutter_actor_get_y(actor) + clutter_actor_get_height(actor) / 2); 1427 | clutter_actor_set_opacity(sc, 160); 1428 | selected_item = item; 1429 | start_x = event->x; 1430 | start_y = event->y; 1431 | } 1432 | g_mutex_unlock(selected_mutex); 1433 | 1434 | return TRUE; 1435 | } 1436 | 1437 | static gboolean subitem_button_release_cb(ClutterActor *actor, ClutterButtonEvent *event, gpointer user_data) 1438 | { 1439 | if (!user_data) { 1440 | return FALSE; 1441 | } 1442 | 1443 | /* discard double clicks */ 1444 | if (event->click_count > 1) { 1445 | return FALSE; 1446 | } 1447 | 1448 | SBItem *item = (SBItem*)user_data; 1449 | if (!item->enabled) { 1450 | return FALSE; 1451 | } 1452 | item->enabled = FALSE; 1453 | 1454 | char *strval = sbitem_get_display_name(item); 1455 | 1456 | g_mutex_lock(selected_mutex); 1457 | debug_printf("%s: %s mouse released\n", __func__, strval); 1458 | 1459 | if (actor) { 1460 | ClutterActor *sc = clutter_actor_get_parent(actor); 1461 | clutter_actor_set_scale_full(sc, 1.0, 1.0, 1462 | clutter_actor_get_x(actor) + 1463 | clutter_actor_get_width(actor) / 2, 1464 | clutter_actor_get_y(actor) + clutter_actor_get_height(actor) / 2); 1465 | clutter_actor_set_opacity(sc, 255); 1466 | 1467 | clutter_actor_reparent(sc, folder); 1468 | clutter_actor_set_position(sc, 1469 | clutter_actor_get_x(sc), clutter_actor_get_y(sc) - (split_pos + clutter_actor_get_y(aniupper))); 1470 | } 1471 | 1472 | selected_item = NULL; 1473 | gui_folder_align_icons(selected_folder, TRUE); 1474 | start_x = 0.0; 1475 | start_y = 0.0; 1476 | 1477 | clutter_threads_add_timeout(ICON_MOVEMENT_DURATION, (GSourceFunc)item_enable, (gpointer)item); 1478 | 1479 | g_mutex_unlock(selected_mutex); 1480 | 1481 | if (selected_folder) 1482 | gui_folder_redraw_subitems(selected_folder); 1483 | 1484 | return TRUE; 1485 | } 1486 | 1487 | static void gui_folder_draw_subitems(SBItem *item) 1488 | { 1489 | ClutterActor *grp = clutter_actor_get_parent(item->texture); 1490 | ClutterActor *minigrp = clutter_group_new(); 1491 | clutter_actor_set_name(minigrp, "mini"); 1492 | clutter_container_add_actor(CLUTTER_CONTAINER(grp), minigrp); 1493 | guint i; 1494 | for (i = 0; i < g_list_length(item->subitems); i++) { 1495 | SBItem *subitem = (SBItem*)g_list_nth_data(item->subitems, i); 1496 | if (subitem && subitem->texture && !subitem->drawn && subitem->node) { 1497 | subitem->is_dock_item = FALSE; 1498 | ClutterActor *sgrp = clutter_group_new(); 1499 | ClutterActor *actor; 1500 | // icon shadow 1501 | actor = subitem->texture_shadow; 1502 | if (actor) { 1503 | clutter_container_add_actor(CLUTTER_CONTAINER(sgrp), actor); 1504 | clutter_actor_set_position(actor, -12.0, -12.0); 1505 | clutter_actor_show(actor); 1506 | } 1507 | // label shadow 1508 | actor = subitem->label_shadow; 1509 | if (actor) { 1510 | clutter_container_add_actor(CLUTTER_CONTAINER(sgrp), actor); 1511 | clutter_actor_set_position(actor, (device_info->home_screen_icon_width - clutter_actor_get_width(actor)) / 2 + 1.0, device_info->home_screen_icon_height + 1.0); 1512 | clutter_actor_show(actor); 1513 | } 1514 | 1515 | actor = subitem->texture; 1516 | clutter_container_add_actor(CLUTTER_CONTAINER(sgrp), actor); 1517 | clutter_actor_set_position(actor, 0.0, 0.0); 1518 | clutter_actor_set_reactive(actor, TRUE); 1519 | g_signal_connect(actor, "button-press-event", G_CALLBACK(subitem_button_press_cb), subitem); 1520 | g_signal_connect(actor, "button-release-event", G_CALLBACK(subitem_button_release_cb), subitem); 1521 | clutter_actor_show(actor); 1522 | 1523 | /* setup label */ 1524 | actor = subitem->label; 1525 | clutter_actor_set_position(actor, (device_info->home_screen_icon_width - clutter_actor_get_width(actor)) / 2, device_info->home_screen_icon_height); 1526 | clutter_text_set_color(CLUTTER_TEXT(actor), &item_text_color); 1527 | clutter_actor_show(actor); 1528 | clutter_container_add_actor(CLUTTER_CONTAINER(sgrp), actor); 1529 | clutter_container_add_actor(CLUTTER_CONTAINER(grp), sgrp); 1530 | clutter_actor_hide(sgrp); 1531 | 1532 | ClutterActor *suba = clutter_clone_new(subitem->texture); 1533 | clutter_actor_unparent(suba); 1534 | clutter_container_add_actor(CLUTTER_CONTAINER(minigrp), suba); 1535 | clutter_actor_set_scale(suba, 0.22, 0.22); 1536 | clutter_actor_set_position(suba, 8.0 + (i%3)*ICON_SPACING, 8.0 + ((double)(int)((int)i/3))*ICON_SPACING); 1537 | if (i < 9) 1538 | clutter_actor_show(suba); 1539 | else 1540 | clutter_actor_hide(suba); 1541 | subitem->drawn = TRUE; 1542 | } 1543 | } 1544 | } 1545 | 1546 | static void gui_show_icons() 1547 | { 1548 | guint i; 1549 | guint j; 1550 | gfloat ypos; 1551 | gfloat xpos; 1552 | 1553 | if (dockitems) { 1554 | xpos = 0.0; 1555 | ypos = 0.0; 1556 | debug_printf("%s: showing dock icons\n", __func__); 1557 | for (i = 0; i < g_list_length(dockitems); i++) { 1558 | SBItem *item = (SBItem*)g_list_nth_data(dockitems, i); 1559 | if (item && item->texture && !item->drawn && item->node) { 1560 | item->is_dock_item = TRUE; 1561 | ClutterActor *grp = clutter_group_new(); 1562 | ClutterActor *actor; 1563 | // icon shadow 1564 | actor = item->texture_shadow; 1565 | if (actor) { 1566 | clutter_container_add_actor(CLUTTER_CONTAINER(grp), actor); 1567 | clutter_actor_set_position(actor, xpos-12, ypos-12); 1568 | } 1569 | // label shadow 1570 | actor = item->label_shadow; 1571 | if (actor) { 1572 | clutter_container_add_actor(CLUTTER_CONTAINER(grp), actor); 1573 | clutter_actor_set_position(actor, xpos + (device_info->home_screen_icon_width - clutter_actor_get_width(actor)) / 2 + 1.0, ypos + device_info->home_screen_icon_height + 1.0); 1574 | } 1575 | actor = item->texture; 1576 | clutter_container_add_actor(CLUTTER_CONTAINER(grp), actor); 1577 | clutter_actor_set_position(actor, xpos, ypos); 1578 | clutter_actor_set_reactive(actor, TRUE); 1579 | g_signal_connect(actor, "button-press-event", G_CALLBACK(item_button_press_cb), item); 1580 | g_signal_connect(actor, "button-release-event", G_CALLBACK(item_button_release_cb), item); 1581 | clutter_actor_show(actor); 1582 | actor = item->label; 1583 | clutter_actor_set_position(actor, xpos + (device_info->home_screen_icon_width - clutter_actor_get_width(actor)) / 2, ypos + device_info->home_screen_icon_height); 1584 | clutter_text_set_color(CLUTTER_TEXT(actor), &dock_item_text_color); 1585 | clutter_container_add_actor(CLUTTER_CONTAINER(grp), actor); 1586 | clutter_container_add_actor(CLUTTER_CONTAINER(the_dock), grp); 1587 | item->drawn = TRUE; 1588 | } 1589 | /* process subitems */ 1590 | if (item->texture && item->is_folder && item->subitems) { 1591 | gui_folder_draw_subitems(item); 1592 | } 1593 | } 1594 | gui_dock_align_icons(FALSE); 1595 | } 1596 | clutter_stage_ensure_redraw(CLUTTER_STAGE(stage)); 1597 | if (sbpages) { 1598 | debug_printf("%s: processing %d pages\n", __func__, g_list_length(sbpages)); 1599 | for (j = 0; j < g_list_length(sbpages); j++) { 1600 | GList *cpage = g_list_nth_data(sbpages, j); 1601 | ypos = 0.0; 1602 | xpos = 0.0; 1603 | debug_printf("%s: showing page icons for page %d\n", __func__, j); 1604 | for (i = 0; i < g_list_length(cpage); i++) { 1605 | SBItem *item = (SBItem*)g_list_nth_data(cpage, i); 1606 | if (item && item->texture && !item->drawn && item->node) { 1607 | item->is_dock_item = FALSE; 1608 | ClutterActor *grp = clutter_group_new(); 1609 | ClutterActor *actor; 1610 | // icon shadow 1611 | actor = item->texture_shadow; 1612 | if (actor) { 1613 | clutter_container_add_actor(CLUTTER_CONTAINER(grp), actor); 1614 | clutter_actor_set_position(actor, xpos-12.0, ypos-12.0); 1615 | } 1616 | 1617 | // label shadow 1618 | actor = item->label_shadow; 1619 | if (actor) { 1620 | clutter_container_add_actor(CLUTTER_CONTAINER(grp), actor); 1621 | clutter_actor_set_position(actor, xpos + (device_info->home_screen_icon_width - clutter_actor_get_width(actor)) / 2 + 1.0, ypos + device_info->home_screen_icon_height + 1.0); 1622 | } 1623 | actor = item->texture; 1624 | clutter_container_add_actor(CLUTTER_CONTAINER(grp), actor); 1625 | clutter_actor_set_position(actor, xpos, ypos); 1626 | clutter_actor_set_reactive(actor, TRUE); 1627 | g_signal_connect(actor, "button-press-event", G_CALLBACK(item_button_press_cb), item); 1628 | g_signal_connect(actor, "button-release-event", G_CALLBACK(item_button_release_cb), item); 1629 | clutter_actor_show(actor); 1630 | actor = item->label; 1631 | clutter_text_set_color(CLUTTER_TEXT(actor), &item_text_color); 1632 | clutter_actor_set_position(actor, xpos + (device_info->home_screen_icon_width - clutter_actor_get_width(actor)) / 2, ypos + device_info->home_screen_icon_height); 1633 | clutter_container_add_actor(CLUTTER_CONTAINER(grp), actor); 1634 | clutter_container_add_actor(CLUTTER_CONTAINER(the_sb), grp); 1635 | item->drawn = TRUE; 1636 | } 1637 | /* process subitems */ 1638 | if (item->texture && item->is_folder && item->subitems) { 1639 | gui_folder_draw_subitems(item); 1640 | } 1641 | } 1642 | gui_page_align_icons(j, FALSE); 1643 | } 1644 | } 1645 | clutter_stage_ensure_redraw(CLUTTER_STAGE(stage)); 1646 | } 1647 | 1648 | static void sbitem_texture_load_finished(ClutterTexture *texture, gpointer error, gpointer data) 1649 | { 1650 | SBItem *item = (SBItem *)data; 1651 | 1652 | if (item->texture_shadow) { 1653 | clutter_actor_show(item->texture_shadow); 1654 | } 1655 | clutter_actor_show(item->label); 1656 | if (item->label_shadow) { 1657 | clutter_actor_show(item->label_shadow); 1658 | } 1659 | } 1660 | 1661 | static gboolean sbitem_texture_new(gpointer data) 1662 | { 1663 | SBItem *item = (SBItem *)data; 1664 | char *icon_filename; 1665 | if (item->is_folder) { 1666 | icon_filename = g_strdup(SBMGR_DATA "/folder.png"); 1667 | } else { 1668 | icon_filename = sbitem_get_icon_filename(item); 1669 | } 1670 | GError *err = NULL; 1671 | 1672 | /* create and load texture */ 1673 | ClutterActor *actor = clutter_texture_new(); 1674 | clutter_texture_set_load_async(CLUTTER_TEXTURE(actor), TRUE); 1675 | g_signal_connect(actor, "load-finished", G_CALLBACK(sbitem_texture_load_finished), (gpointer)item); 1676 | clutter_actor_set_size(actor, device_info->home_screen_icon_width, device_info->home_screen_icon_height); 1677 | clutter_actor_set_scale(actor, 1.0, 1.0); 1678 | 1679 | /* create item */ 1680 | item->texture = actor; 1681 | 1682 | if (wallpaper) { 1683 | actor = clutter_clone_new(icon_shadow); 1684 | clutter_actor_hide(actor); 1685 | clutter_actor_set_size(actor, device_info->home_screen_icon_width+24.0, device_info->home_screen_icon_height+24.0); 1686 | item->texture_shadow = actor; 1687 | } 1688 | 1689 | char *txtval = sbitem_get_display_name(item); 1690 | if (txtval) { 1691 | item->label = clutter_text_new_with_text(ITEM_FONT, txtval); 1692 | clutter_actor_hide(item->label); 1693 | if (wallpaper) { 1694 | item->label_shadow = clutter_text_new_full(ITEM_FONT, txtval, &label_shadow_color); 1695 | clutter_actor_hide(item->label_shadow); 1696 | } 1697 | } 1698 | if (err) { 1699 | fprintf(stderr, "ERROR: %s\n", err->message); 1700 | g_error_free(err); 1701 | } 1702 | 1703 | clutter_texture_set_from_file(CLUTTER_TEXTURE(item->texture), icon_filename, &err); 1704 | 1705 | /* FIXME: Optimize! Do not traverse whole iconlist, just this icon */ 1706 | gui_show_icons(); 1707 | 1708 | g_mutex_lock(icon_loader_mutex); 1709 | icons_loaded++; 1710 | g_mutex_unlock(icon_loader_mutex); 1711 | 1712 | return FALSE; 1713 | } 1714 | 1715 | static gpointer sbitem_thread_load_texture(gpointer data) 1716 | { 1717 | SBItem *item = (SBItem *)data; 1718 | char *icon_filename = sbitem_get_icon_filename(item); 1719 | char *display_identifier = sbitem_get_display_identifier(item); 1720 | GError *err = NULL; 1721 | 1722 | debug_printf("%s: loading icon texture for '%s'\n", __func__, display_identifier); 1723 | 1724 | if (device_sbs_save_icon(sbc, display_identifier, icon_filename, &err)) { 1725 | /* load texture in the clutter main loop */ 1726 | clutter_threads_add_idle((GSourceFunc)sbitem_texture_new, item); 1727 | } else { 1728 | fprintf(stderr, "ERROR: %s\n", err->message); 1729 | g_error_free(err); 1730 | } 1731 | g_free(icon_filename); 1732 | 1733 | return NULL; 1734 | } 1735 | 1736 | static guint gui_load_icon_row(plist_t items, GList **row) 1737 | { 1738 | int i; 1739 | int count; 1740 | int icon_count = 0; 1741 | SBItem *item = NULL; 1742 | 1743 | count = plist_array_get_size(items); 1744 | for (i = 0; i < count; i++) { 1745 | plist_t icon_info = plist_array_get_item(items, i); 1746 | plist_t subitems = plist_dict_get_item(icon_info, "iconLists"); 1747 | if (subitems) { 1748 | /* this is a folder, so we need to load the subitems */ 1749 | GList *folderitems = NULL; 1750 | if (plist_get_node_type(subitems) == PLIST_ARRAY) { 1751 | subitems = plist_array_get_item(subitems, 0); 1752 | if (plist_get_node_type(subitems) == PLIST_ARRAY) { 1753 | icon_count += gui_load_icon_row(subitems, &folderitems); 1754 | } 1755 | } 1756 | if (folderitems) { 1757 | item = sbitem_new_with_subitems(icon_info, folderitems); 1758 | if (item != NULL) { 1759 | clutter_threads_add_idle((GSourceFunc)sbitem_texture_new, item); 1760 | *row = g_list_append(*row, item); 1761 | icon_count++; 1762 | } 1763 | } 1764 | } else { 1765 | item = sbitem_new(icon_info); 1766 | if (item != NULL) { 1767 | /* load texture of icon in a new thread */ 1768 | g_thread_create(sbitem_thread_load_texture, item, FALSE, NULL); 1769 | 1770 | *row = g_list_append(*row, item); 1771 | icon_count++; 1772 | } 1773 | } 1774 | } 1775 | 1776 | return icon_count; 1777 | } 1778 | 1779 | static void gui_set_iconstate(plist_t iconstate, const char *format_version) 1780 | { 1781 | int total; 1782 | 1783 | /* get total number of pages */ 1784 | if (plist_get_node_type(iconstate) != PLIST_ARRAY) { 1785 | fprintf(stderr, "ERROR: Invalid icon state format!\n"); 1786 | return; 1787 | } 1788 | 1789 | total = plist_array_get_size(iconstate); 1790 | if (total < 1) { 1791 | fprintf(stderr, "ERROR: No icons returned in icon state\n"); 1792 | return; 1793 | } else { 1794 | plist_t dock = plist_array_get_item(iconstate, 0); 1795 | if ((plist_get_node_type(dock) != PLIST_ARRAY) 1796 | || (plist_array_get_size(dock) < 1)) { 1797 | fprintf(stderr, "ERROR: error getting outer dock icon array!\n"); 1798 | return; 1799 | } 1800 | 1801 | if (!format_version || (strcmp(format_version, "2") != 0)) { 1802 | dock = plist_array_get_item(dock, 0); 1803 | if (plist_get_node_type(dock) != PLIST_ARRAY) { 1804 | fprintf(stderr, "ERROR: error getting inner dock icon array!\n"); 1805 | return; 1806 | } 1807 | } 1808 | 1809 | /* load dock icons */ 1810 | debug_printf("%s: processing dock\n", __func__); 1811 | total_icons += gui_load_icon_row(dock, &dockitems); 1812 | num_dock_items = g_list_length(dockitems); 1813 | if (total > 1) { 1814 | /* get all page icons */ 1815 | int p, r, rows; 1816 | for (p = 1; p < total; p++) { 1817 | plist_t npage = plist_array_get_item(iconstate, p); 1818 | GList *page = NULL; 1819 | if ((plist_get_node_type(npage) != PLIST_ARRAY) 1820 | || (plist_array_get_size(npage) < 1)) { 1821 | fprintf(stderr, "ERROR: error getting outer page icon array!\n"); 1822 | return; 1823 | } 1824 | 1825 | if (!format_version || (strcmp(format_version, "2") != 0)) { 1826 | /* rows */ 1827 | rows = plist_array_get_size(npage); 1828 | for (r = 0; r < rows; r++) { 1829 | debug_printf("%s: processing page %d, row %d\n", __func__, p, r); 1830 | 1831 | plist_t nrow = plist_array_get_item(npage, r); 1832 | if (plist_get_node_type(nrow) != PLIST_ARRAY) { 1833 | fprintf(stderr, "ERROR: error getting page row icon array!\n"); 1834 | return; 1835 | } 1836 | total_icons += gui_load_icon_row(nrow, &page); 1837 | } 1838 | } else { 1839 | total_icons += gui_load_icon_row(npage, &page); 1840 | } 1841 | 1842 | if (page) { 1843 | sbpages = g_list_append(sbpages, page); 1844 | gui_page_indicator_group_add(page, p - 1); 1845 | } 1846 | } 1847 | } 1848 | } 1849 | } 1850 | 1851 | static void gui_disable_controls() 1852 | { 1853 | gui_fade_start(); 1854 | gui_spinner_start(); 1855 | } 1856 | 1857 | static void gui_enable_controls() 1858 | { 1859 | gui_spinner_stop(); 1860 | gui_fade_stop(); 1861 | } 1862 | 1863 | static gboolean wait_icon_load_finished(gpointer user_data) 1864 | { 1865 | gboolean res = TRUE; 1866 | g_mutex_lock(icon_loader_mutex); 1867 | debug_printf("%d of %d icons loaded (%d%%)\n", icons_loaded, total_icons, (int)(100*((double)icons_loaded/(double)total_icons))); 1868 | if (icons_loaded >= total_icons) { 1869 | gui_enable_controls(); 1870 | res = FALSE; 1871 | if (finished_callback) { 1872 | finished_callback(TRUE); 1873 | finished_callback = NULL; 1874 | } 1875 | } 1876 | g_mutex_unlock(icon_loader_mutex); 1877 | return res; 1878 | } 1879 | 1880 | #ifdef HAVE_LIBIMOBILEDEVICE_1_1 1881 | static void gui_set_wallpaper(const char *wp) 1882 | { 1883 | GError *err = NULL; 1884 | wallpaper = NULL; 1885 | ClutterActor *actor = clutter_texture_new(); 1886 | clutter_texture_set_load_async(CLUTTER_TEXTURE(actor), TRUE); 1887 | clutter_texture_set_from_file(CLUTTER_TEXTURE(actor), wp, &err); 1888 | if (err) { 1889 | g_error_free(err); 1890 | err = NULL; 1891 | return; 1892 | } 1893 | clutter_actor_set_size(actor, stage_area.x2, stage_area.y2); 1894 | clutter_actor_set_position(actor, 0, 0); 1895 | clutter_actor_show(actor); 1896 | clutter_group_add(CLUTTER_GROUP(stage), actor); 1897 | clutter_actor_lower_bottom(actor); 1898 | wallpaper = actor; 1899 | item_text_color.alpha = 255; 1900 | } 1901 | #endif 1902 | 1903 | static gboolean gui_pages_init_cb(gpointer user_data) 1904 | { 1905 | const char *uuid = (const char*)user_data; 1906 | GError *error = NULL; 1907 | plist_t iconstate = NULL; 1908 | 1909 | gui_disable_controls(); 1910 | icons_loaded = 0; 1911 | total_icons = 0; 1912 | 1913 | if (selected_folder) { 1914 | folderview_close_finish(selected_folder); 1915 | } 1916 | 1917 | pages_free(); 1918 | 1919 | /* connect to sbservices */ 1920 | if (!sbc) 1921 | sbc = device_sbs_new(uuid, &osversion, &error); 1922 | 1923 | if (error) { 1924 | g_printerr("%s", error->message); 1925 | g_error_free(error); 1926 | error = NULL; 1927 | } 1928 | 1929 | if (sbc) { 1930 | const char *fmt_version = NULL; 1931 | #ifdef HAVE_LIBIMOBILEDEVICE_1_1 1932 | if (osversion >= 0x04000000) { 1933 | fmt_version = "2"; 1934 | } 1935 | 1936 | /* Load wallpaper if available */ 1937 | if (osversion >= 0x03020000) { 1938 | char *path; 1939 | path = device_sbs_save_wallpaper(sbc, uuid, &error); 1940 | if (path == NULL) { 1941 | g_printerr("%s", error->message); 1942 | g_error_free(error); 1943 | error = NULL; 1944 | } else { 1945 | gui_set_wallpaper(path); 1946 | } 1947 | g_free (path); 1948 | } 1949 | #endif 1950 | /* Load icon data */ 1951 | if (device_sbs_get_iconstate(sbc, &iconstate, fmt_version, &error)) { 1952 | gui_set_iconstate(iconstate, fmt_version); 1953 | plist_free(iconstate); 1954 | } 1955 | } 1956 | 1957 | if (error) { 1958 | g_printerr("%s", error->message); 1959 | g_error_free(error); 1960 | error = NULL; 1961 | } 1962 | 1963 | clutter_threads_add_timeout(500, (GSourceFunc)wait_icon_load_finished, NULL); 1964 | 1965 | return FALSE; 1966 | } 1967 | 1968 | static gboolean update_device_info_cb(gpointer user_data) 1969 | { 1970 | device_info_t di = (device_info_t)user_data; 1971 | if (di) { 1972 | clutter_text_set_text(CLUTTER_TEXT(type_label), di->device_type); 1973 | } else { 1974 | clutter_text_set_text(CLUTTER_TEXT(type_label), NULL); 1975 | } 1976 | return FALSE; 1977 | } 1978 | 1979 | static gboolean update_battery_info_cb(gpointer user_data) 1980 | { 1981 | const char *uuid = (const char*)user_data; 1982 | GError *error = NULL; 1983 | gboolean res = TRUE; 1984 | 1985 | if (gui_deinitialized) { 1986 | return FALSE; 1987 | } 1988 | 1989 | if (device_poll_battery_capacity(uuid, &device_info, &error)) { 1990 | clutter_actor_set_size(battery_level, (guint) (((double) (device_info->battery_capacity) / 100.0) * 15), 6); 1991 | if (device_info->battery_capacity == 100) { 1992 | res = FALSE; 1993 | } 1994 | } 1995 | return res; 1996 | } 1997 | 1998 | static gboolean init_battery_info_cb(gpointer user_data) 1999 | { 2000 | clutter_actor_set_size(battery_level, (guint) (((double) (device_info->battery_capacity) / 100.0) * 15), 6); 2001 | return FALSE; 2002 | } 2003 | 2004 | void gui_pages_free() 2005 | { 2006 | clutter_threads_add_timeout(0, (GSourceFunc)(update_device_info_cb), NULL); 2007 | pages_free(); 2008 | if (sbc) { 2009 | device_sbs_free(sbc); 2010 | sbc = NULL; 2011 | osversion = 0; 2012 | } 2013 | } 2014 | 2015 | static void gui_update_layout(device_info_t info) { 2016 | if (!info) 2017 | return; 2018 | 2019 | /* calculate stage boundry */ 2020 | stage_area.x1 = 0.0; 2021 | stage_area.y1 = 0.0; 2022 | stage_area.x2 = (info->home_screen_icon_width * MAX(info->home_screen_icon_columns, info->home_screen_icon_dock_max_count)); 2023 | stage_area.x2 += (ICON_SPACING * MAX(info->home_screen_icon_columns, info->home_screen_icon_dock_max_count)); 2024 | stage_area.x2 += ICON_SPACING + 2; 2025 | 2026 | stage_area.y2 = (info->home_screen_icon_height * info->home_screen_icon_rows); 2027 | stage_area.y2 += ((ICON_SPACING*2) * info->home_screen_icon_rows); 2028 | stage_area.y2 += DOCK_HEIGHT; 2029 | 2030 | printf("%s: stage_area x: %f, y: %f, width: %f, height: %f\n", __func__, stage_area.x1, stage_area.y1, stage_area.x2, stage_area.y2); 2031 | 2032 | /* update areas */ 2033 | dock_area.x1 = 0.0; 2034 | dock_area.y1 = stage_area.y2 - DOCK_HEIGHT - (ICON_SPACING / 2); 2035 | dock_area.x2 = stage_area.x2; 2036 | dock_area.y2 = stage_area.y2; 2037 | 2038 | printf("%s: dock_area x: %f, y: %f, width: %f, height: %f\n", __func__, dock_area.x1, dock_area.y1, dock_area.x2, dock_area.y2); 2039 | 2040 | sb_area.x1 = 0.0; 2041 | sb_area.y1 = ICON_SPACING; 2042 | sb_area.x2 = stage_area.x2; 2043 | sb_area.y2 = dock_area.y1; 2044 | 2045 | printf("%s: sb_area x: %f, y: %f, width: %f, height: %f\n", __func__, sb_area.x1, sb_area.y1, sb_area.x2, sb_area.y2); 2046 | 2047 | /* update triggers */ 2048 | left_trigger.x1 = -ICON_SPACING - 2; 2049 | left_trigger.y1 = ICON_SPACING; 2050 | left_trigger.x2 = -(ICON_SPACING / 2); 2051 | left_trigger.y2 = stage_area.y2 - DOCK_HEIGHT - ICON_SPACING; 2052 | 2053 | printf("%s: left_trigger x: %f, y: %f, width: %f, height: %f\n", __func__, left_trigger.x1, left_trigger.y1, left_trigger.x2, left_trigger.y2); 2054 | 2055 | right_trigger.x1 = stage_area.x2 + (ICON_SPACING / 2); 2056 | right_trigger.y1 = ICON_SPACING; 2057 | right_trigger.x2 = stage_area.x2 + (ICON_SPACING*2); 2058 | right_trigger.y2 = stage_area.y2 - DOCK_HEIGHT - ICON_SPACING; 2059 | 2060 | printf("%s: right_trigger x: %f, y: %f, width: %f, height: %f\n", __func__, right_trigger.x1, right_trigger.y1, right_trigger.x2, right_trigger.y2); 2061 | 2062 | /* update widget to new layout */ 2063 | gtk_widget_set_size_request(clutter_gtk_widget, stage_area.x2, stage_area.y2); 2064 | clutter_actor_set_position(the_dock, dock_area.x1, dock_area.y1); 2065 | clutter_actor_set_position(page_indicator_group, 0, stage_area.y2 - DOCK_HEIGHT - ICON_SPACING); 2066 | clutter_actor_set_position(the_sb, sb_area.x1, sb_area.y1); 2067 | clutter_actor_set_position(battery_level, stage_area.x2 - 22, 6); 2068 | clutter_actor_set_position(spinner, (stage_area.x2 - 32.0) / 2, (stage_area.y2 - 64.0) / 2); 2069 | clutter_actor_set_size(fade_rectangle, stage_area.x2, stage_area.y2); 2070 | 2071 | #ifdef HAVE_LIBIMOBILEDEVICE_1_1 2072 | clutter_actor_set_size(wallpaper, stage_area.x2, stage_area.y2); 2073 | #endif 2074 | } 2075 | 2076 | static gboolean device_info_cb(gpointer user_data) 2077 | { 2078 | GError *error = NULL; 2079 | const char *uuid = (const char*)user_data; 2080 | if (device_get_info(uuid, &device_info, &error)) { 2081 | /* Update layout */ 2082 | gui_update_layout(device_info); 2083 | /* Update device info */ 2084 | clutter_threads_add_idle((GSourceFunc)update_device_info_cb, device_info); 2085 | /* Update battery information */ 2086 | clutter_threads_add_idle((GSourceFunc)init_battery_info_cb, NULL); 2087 | /* Register battery state read timeout */ 2088 | clutter_threads_add_timeout(device_info->battery_poll_interval * 1000, (GSourceFunc)update_battery_info_cb, (gpointer)uuid); 2089 | 2090 | if (device_info_callback) { 2091 | device_info_callback(device_info->device_name, device_info->device_name); 2092 | device_info_callback = NULL; 2093 | } 2094 | } else { 2095 | if (error) { 2096 | g_printerr("%s", error->message); 2097 | g_error_free(error); 2098 | } else { 2099 | g_printerr(_("Unknown error occurred")); 2100 | } 2101 | if (finished_callback) { 2102 | finished_callback(FALSE); 2103 | finished_callback = NULL; 2104 | } 2105 | } 2106 | return FALSE; 2107 | } 2108 | 2109 | void gui_pages_load(const char *uuid, device_info_cb_t info_cb, finished_cb_t finished_cb) 2110 | { 2111 | printf("%s: %s\n", __func__, uuid); 2112 | finished_callback = finished_cb; 2113 | device_info_callback = info_cb; 2114 | 2115 | /* Load icons */ 2116 | clutter_threads_add_idle((GSourceFunc)gui_pages_init_cb, (gpointer)uuid); 2117 | 2118 | /* Load device information */ 2119 | g_thread_create((GThreadFunc)device_info_cb, (gpointer)uuid, FALSE, NULL); 2120 | } 2121 | 2122 | GtkWidget *gui_init() 2123 | { 2124 | device_info = device_info_new(); 2125 | ClutterActor *actor; 2126 | 2127 | if (!g_thread_supported()) 2128 | g_thread_init(NULL); 2129 | 2130 | if (icon_loader_mutex == NULL) 2131 | icon_loader_mutex = g_mutex_new(); 2132 | 2133 | /* initialize clutter threading environment */ 2134 | if (!clutter_threads_initialized) { 2135 | clutter_threads_init(); 2136 | clutter_threads_initialized = 1; 2137 | } 2138 | 2139 | if (!clutter_initialized) { 2140 | g_setenv ("CLUTTER_VBLANK", "none", FALSE); 2141 | if (gtk_clutter_init(NULL, NULL) != CLUTTER_INIT_SUCCESS) { 2142 | g_error("Unable to initialize GtkClutter"); 2143 | return NULL; 2144 | } 2145 | clutter_initialized = 1; 2146 | } 2147 | 2148 | gettimeofday(&last_page_switch, NULL); 2149 | 2150 | /* Create the clutter widget */ 2151 | GtkWidget *clutter_widget = clutter_gtk_widget = gtk_clutter_embed_new(); 2152 | 2153 | /* Set the size of the widget, because we should not set the size of its 2154 | * stage when using GtkClutterEmbed. 2155 | */ 2156 | gtk_widget_set_size_request(clutter_widget, stage_area.x2, stage_area.y2); 2157 | 2158 | /* Set the stage background color */ 2159 | stage = gtk_clutter_embed_get_stage(GTK_CLUTTER_EMBED(clutter_widget)); 2160 | clutter_stage_set_color(CLUTTER_STAGE(stage), &stage_color); 2161 | 2162 | /* attach to stage signals */ 2163 | g_signal_connect(stage, "motion-event", G_CALLBACK(stage_motion_cb), NULL); 2164 | g_signal_connect(stage, "key-press-event", G_CALLBACK(stage_key_press_cb), NULL); 2165 | 2166 | /* Load ui background */ 2167 | GError *err = NULL; 2168 | actor = clutter_texture_new(); 2169 | clutter_texture_set_load_async(CLUTTER_TEXTURE(actor), TRUE); 2170 | clutter_texture_set_from_file(CLUTTER_TEXTURE(actor), SBMGR_DATA "/background.png", &err); 2171 | if (err) { 2172 | g_error_free(err); 2173 | err = NULL; 2174 | } 2175 | if (actor) { 2176 | clutter_actor_set_position(actor, 0, 0); 2177 | clutter_actor_show(actor); 2178 | clutter_group_add(CLUTTER_GROUP(stage), actor); 2179 | } else { 2180 | fprintf(stderr, "could not load background.png\n"); 2181 | } 2182 | 2183 | /* Create device type widget */ 2184 | type_label = clutter_text_new_full(CLOCK_FONT, "", &clock_text_color); 2185 | clutter_group_add(CLUTTER_GROUP(stage), type_label); 2186 | clutter_actor_set_position(type_label, 3.0, 2.0); 2187 | 2188 | /* clock widget */ 2189 | clock_label = clutter_text_new_full(CLOCK_FONT, "00:00", &clock_text_color); 2190 | clutter_group_add(CLUTTER_GROUP(stage), clock_label); 2191 | 2192 | /* page indicator group for holding the page indicator dots */ 2193 | page_indicator_group = clutter_group_new(); 2194 | clutter_group_add(CLUTTER_GROUP(stage), page_indicator_group); 2195 | 2196 | /* alignment will be done when new indicators are added */ 2197 | clutter_actor_set_position(page_indicator_group, 0, stage_area.y2 - DOCK_HEIGHT - ICON_SPACING); 2198 | 2199 | /* page indicator (dummy), will be cloned when the pages are created */ 2200 | page_indicator = clutter_texture_new(); 2201 | clutter_texture_set_load_async(CLUTTER_TEXTURE(page_indicator), TRUE); 2202 | clutter_texture_set_from_file(CLUTTER_TEXTURE(page_indicator), SBMGR_DATA "/dot.png", &err); 2203 | if (err) { 2204 | fprintf(stderr, "Could not load texture " SBMGR_DATA "/dot.png" ": %s\n", err->message); 2205 | g_error_free(err); 2206 | err = NULL; 2207 | } 2208 | if (page_indicator) { 2209 | clutter_actor_hide(page_indicator); 2210 | clutter_container_add_actor(CLUTTER_CONTAINER(stage), page_indicator); 2211 | } 2212 | 2213 | /* icon shadow texture dummy, cloned when drawing the icons */ 2214 | icon_shadow = clutter_texture_new(); 2215 | clutter_texture_set_load_async(CLUTTER_TEXTURE(icon_shadow), TRUE); 2216 | clutter_texture_set_from_file(CLUTTER_TEXTURE(icon_shadow), SBMGR_DATA "/iconshadow.png", &err); 2217 | if (err) { 2218 | fprintf(stderr, "Could not load texture " SBMGR_DATA "/iconshadow.png" ": %s\n", err->message); 2219 | g_error_free(err); 2220 | err = NULL; 2221 | } 2222 | if (icon_shadow) { 2223 | clutter_actor_hide(icon_shadow); 2224 | clutter_container_add_actor(CLUTTER_CONTAINER(stage), icon_shadow); 2225 | } 2226 | 2227 | /* folder marker */ 2228 | folder_marker = clutter_texture_new(); 2229 | clutter_texture_set_load_async(CLUTTER_TEXTURE(folder_marker), TRUE); 2230 | clutter_texture_set_from_file(CLUTTER_TEXTURE(folder_marker), SBMGR_DATA "/foldermarker.png", &err); 2231 | if (err) { 2232 | fprintf(stderr, "Could not load texture " SBMGR_DATA "/foldermarker.png" ": %s\n", err->message); 2233 | g_error_free(err); 2234 | err = NULL; 2235 | } 2236 | if (folder_marker) { 2237 | clutter_actor_hide(folder_marker); 2238 | clutter_container_add_actor(CLUTTER_CONTAINER(stage), folder_marker); 2239 | } 2240 | 2241 | /* a group for the springboard icons */ 2242 | the_sb = clutter_group_new(); 2243 | clutter_group_add(CLUTTER_GROUP(stage), the_sb); 2244 | clutter_actor_set_position(the_sb, sb_area.x1, sb_area.y1); 2245 | 2246 | /* a group for the dock icons */ 2247 | the_dock = clutter_group_new(); 2248 | clutter_group_add(CLUTTER_GROUP(stage), the_dock); 2249 | clutter_actor_set_position(the_dock, dock_area.x1, dock_area.y1); 2250 | 2251 | gui_fade_init(); 2252 | gui_spinner_init(); 2253 | 2254 | /* Show the stage */ 2255 | clutter_actor_show(stage); 2256 | 2257 | /* Create a timeline to manage animation */ 2258 | clock_timeline = clutter_timeline_new(200); 2259 | clutter_timeline_set_loop(clock_timeline, TRUE); /* have it loop */ 2260 | 2261 | /* fire a callback for frame change */ 2262 | g_signal_connect(clock_timeline, "completed", G_CALLBACK(clock_update_cb), NULL); 2263 | 2264 | /* and start it */ 2265 | clutter_timeline_start(clock_timeline); 2266 | 2267 | if (selected_mutex == NULL) 2268 | selected_mutex = g_mutex_new(); 2269 | 2270 | /* Position and update the clock */ 2271 | clock_set_time(clock_label, time(NULL)); 2272 | clutter_actor_show(clock_label); 2273 | 2274 | /* battery capacity */ 2275 | battery_level = clutter_rectangle_new_with_color(&battery_color); 2276 | clutter_group_add(CLUTTER_GROUP(stage), battery_level); 2277 | clutter_actor_set_position(battery_level, stage_area.x2 - 22, 6); 2278 | 2279 | return clutter_widget; 2280 | } 2281 | 2282 | void gui_deinit() 2283 | { 2284 | clutter_timeline_stop(clock_timeline); 2285 | device_info_free(device_info); 2286 | gui_deinitialized = 1; 2287 | } 2288 | --------------------------------------------------------------------------------