./0000755000004100000410000000000014320114711011235 5ustar www-datawww-data./NEWS0000644000004100000410000000026514320114711011737 0ustar www-datawww-data12.10.2: * fix escape key behavior in calendar menuitem (LP: #953757) 12.10.1: * remove gtk2 support * remove slider hack (lp #953757) 12.10.0: * new widget IdoSwitchMenuItem ./INSTALL0000644000004100000410000002243214320114711012271 0ustar www-datawww-dataInstallation Instructions ************************* Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. (Caching is disabled by default to prevent problems with accidental use of stale cache files.) If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You only need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not support the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' installs the package's commands under `/usr/local/bin', include files under `/usr/local/include', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option `--exec-prefix=PREFIX' to `configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the option `--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). Here is a another example: /bin/bash ./configure CONFIG_SHELL=/bin/bash Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent configuration-related scripts to be executed by `/bin/bash'. `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of the options to `configure', and exit. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. ./configure.ac0000644000004100000410000001047314320114711013530 0ustar www-datawww-data# # shamelessly stolen from clutter-gtk # m4_define([ido_major_version], [13]) m4_define([ido_minor_version], [10]) m4_define([ido_micro_version], [1]) m4_define([ido_api_version], [ido_major_version.ido_minor_version]) m4_define([ido_version], [ido_major_version.ido_minor_version.ido_micro_version]) m4_define([ido_interface_age], [0]) m4_define([ido_binary_age], [m4_eval(100 * ido_minor_version + ido_micro_version)]) AC_PREREQ([2.64]) AC_INIT([ido], [ido_version], [http://bugs.launchpad.net/ido], [ido], [http://launchpad.net/ido]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_SRCDIR([src/libido.h]) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE([check-news 1.11 foreign]) AM_SILENT_RULES([yes]) IDO_MAJOR_VERSION=ido_major_version IDO_MINOR_VERSION=ido_minor_version IDO_MICRO_VERSION=ido_micro_version IDO_VERSION=ido_version AC_SUBST(IDO_MAJOR_VERSION) AC_SUBST(IDO_MINOR_VERSION) AC_SUBST(IDO_MICRO_VERSION) AC_SUBST(IDO_VERSION) m4_define([lt_current], [m4_eval(100 * ido_minor_version + ido_micro_version - ido_interface_age)]) m4_define([lt_revision], [ido_interface_age]) m4_define([lt_age], [m4_eval(ido_binary_age - ido_interface_age)]) IDO_LT_CURRENT=lt_current IDO_LT_REV=lt_revision IDO_LT_AGE=lt_age IDO_LT_VERSION="$IDO_LT_CURRENT:$IDO_LT_REV:$IDO_LT_AGE" IDO_LT_LDFLAGS="-version-info $IDO_LT_VERSION" AC_SUBST(IDO_LT_VERSION) AC_SUBST(IDO_LT_LDFLAGS) dnl =========================================================================== # Checks for programs AC_PROG_CC AM_PROG_CC_C_O AC_PROG_CXX # Initialize libtool LT_PREREQ([2.2]) LT_INIT([disable-static]) AC_PATH_PROG([GLIB_MKENUMS], [glib-mkenums]) PKG_PROG_PKG_CONFIG # Checks for header files AC_HEADER_STDC AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h]) # Checks for typedefs, structures and compiler charecteristics AC_C_CONST # Checks for library functions AC_FUNC_MALLOC AC_FUNC_MMAP AC_CHECK_FUNCS([memset munmap strcasecmp strdup]) AC_CHECK_LIBM GIO_REQUIRED_VERSION=2.37.0 GTK_REQUIRED_VERSION=3.8.2 PKG_CHECK_MODULES(GTK,[gtk+-3.0 >= $GTK_REQUIRED_VERSION gio-2.0 >= $GIO_REQUIRED_VERSION]) AC_SUBST(GTK_CFLAGS) AC_SUBST(GTK_LIBS) dnl =========================================================================== if test "x$GCC" = "xyes"; then GCC_FLAGS="-g -Wall" fi AC_SUBST(GCC_FLAGS) # use strict compiler flags only on development releases m4_define([maintainer_flags_default], [m4_if(m4_eval(ido_minor_version % 2), [1], [yes], [no])]) AC_ARG_ENABLE([maintainer-flags], [AS_HELP_STRING([--enable-maintainer-flags=@<:@no/yes@:>@], [Use strict compiler flags @<:@default=no@:>@])], [], [enable_maintainer_flags=maintainer_flags_default]) MAINTAINER_CFLAGS="" AS_IF([test "x$enable_maintainer_flags" = "xyes" && test "x$GCC" = "xyes"], [ MAINTAINER_CFLAGS="-Werror -Wall -Wshadow -Wcast-align -Wno-uninitialized -Wempty-body -Wformat-security -Winit-self" ] ) AC_SUBST(MAINTAINER_CFLAGS) dnl = gcov Coverage Reporting ================================================= m4_include([m4/gcov.m4]) AC_TDD_GCOV AM_CONDITIONAL([HAVE_GCOV], [test "x$ac_cv_check_gcov" = xyes]) AM_CONDITIONAL([HAVE_LCOV], [test "x$ac_cv_check_lcov" = xyes]) AM_CONDITIONAL([HAVE_GCOVR], [test "x$ac_cv_check_gcovr" = xyes]) AC_SUBST(COVERAGE_CFLAGS) AC_SUBST(COVERAGE_CXXFLAGS) AC_SUBST(COVERAGE_LDFLAGS) dnl = GObject Introspection =================================================== GOBJECT_INTROSPECTION_CHECK([0.6.7]) dnl = Vala API Generation ===================================================== AC_PATH_PROG([VALA_API_GEN], [vapigen]) dnl = Google Test Framework =================================================== dnl xorg-gtest also provides gtest. CHECK_XORG_GTEST dnl = GTK Doc Check =========================================================== GTK_DOC_CHECK([1.8]) dnl =========================================================================== AC_CONFIG_FILES([ Makefile src/Makefile example/Makefile tests/Makefile libido.pc libido3.pc ]) AC_OUTPUT echo "" echo " ido $VERSION" echo " ===============================" echo "" echo " Prefix : ${prefix}" echo " gcov : ${use_gcov}" echo " introspection: ${enable_introspection}" echo "" echo " Documentation: ${enable_gtk_doc}" echo "" ./README0000644000004100000410000000000014320114711012103 0ustar www-datawww-data./example/0000755000004100000410000000000014320114711012670 5ustar www-datawww-data./example/menus.c0000644000004100000410000001203714320114711014166 0ustar www-datawww-data#include #include "idoscalemenuitem.h" #include "idocalendarmenuitem.h" #include "idoentrymenuitem.h" #include "idolocationmenuitem.h" #include "idoswitchmenuitem.h" #include "idousermenuitem.h" #include "config.h" static void slider_grabbed (GtkWidget *widget, gpointer user_data) { g_print ("grabbed\n"); } static void slider_released (GtkWidget *widget, gpointer user_data) { g_print ("released\n"); } int main (int argc, char *argv[]) { guint i; GtkWidget *window; GtkWidget *vbox; GtkWidget *menu; GtkWidget *menuitem; GtkWidget *root; GtkWidget *menubar; GtkWidget *image; const struct { const char * username; const char * icon_filename; gboolean is_logged_in; gboolean is_active; } users[] = { { "Guest", NULL, FALSE, FALSE }, { "Bobby Fischer", "/usr/share/pixmaps/faces/chess.jpg", FALSE, FALSE }, { "Linus Torvalds", "/usr/share/pixmaps/faces/penguin.jpg", TRUE, FALSE }, { "Mark Shuttleworth", "/usr/share/pixmaps/faces/astronaut.jpg", TRUE, TRUE } }; const struct { const char * name; const char * timezone; const char * format; } locations[] = { { "Oklahoma City", "America/Chicago", "%I:%M %p" }, { "Magdeburg", "Europe/Berlin", "%T" }, { "Kuntzig", "Europe/Paris", "%a %H:%M" } }; g_unsetenv ("UBUNTU_MENUPROXY"); gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Menus"); gtk_widget_set_size_request (window, 300, 200); g_signal_connect (window, "delete-event", G_CALLBACK (gtk_main_quit), NULL); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_add (GTK_CONTAINER (window), vbox); menubar = gtk_menu_bar_new (); gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, FALSE, 0); menu = gtk_menu_new (); root = gtk_menu_item_new_with_label ("File"); gtk_menu_item_set_submenu (GTK_MENU_ITEM (root), menu); menuitem = gtk_menu_item_new_with_label ("New"); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); menuitem = gtk_menu_item_new_with_label ("Open"); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); /* Scale */ menuitem = ido_scale_menu_item_new_with_range ("Volume", IDO_RANGE_STYLE_DEFAULT, 65, 0, 100, 1); ido_scale_menu_item_set_style (IDO_SCALE_MENU_ITEM (menuitem), IDO_SCALE_MENU_ITEM_STYLE_IMAGE); image = ido_scale_menu_item_get_primary_image (IDO_SCALE_MENU_ITEM (menuitem)); gtk_image_set_from_stock (GTK_IMAGE (image), GTK_STOCK_NEW, GTK_ICON_SIZE_MENU); image = ido_scale_menu_item_get_secondary_image (IDO_SCALE_MENU_ITEM (menuitem)); gtk_image_set_from_stock (GTK_IMAGE (image), GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); g_signal_connect (menuitem, "slider-grabbed", G_CALLBACK (slider_grabbed), NULL); g_signal_connect (menuitem, "slider-released", G_CALLBACK (slider_released), NULL); /* Entry */ menuitem = ido_entry_menu_item_new (); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); /* Switch */ menuitem = ido_switch_menu_item_new (); ido_switch_menu_item_set_label (IDO_SWITCH_MENU_ITEM (menuitem), "This is a switch."); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); /* Calendar */ gtk_menu_shell_append (GTK_MENU_SHELL (menu), gtk_separator_menu_item_new ()); menuitem = ido_calendar_menu_item_new (); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); /* Users */ gtk_menu_shell_append (GTK_MENU_SHELL (menu), gtk_separator_menu_item_new ()); for (i=0; i #include "idomessagedialog.h" #include "config.h" static void response_cb (GtkDialog *dialog, gint response, gpointer user_data) { gtk_widget_destroy (GTK_WIDGET (dialog)); } static void button_clicked_cb (GtkWidget *button, gpointer data) { GtkWidget *window = (GtkWidget *) data; GtkWidget *dialog = ido_message_dialog_new (GTK_WINDOW (window), GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, "This is a test of the emergency broadcasting system"); gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog), "If this had been an actual emergency, you'd be dead already"); g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (response_cb), NULL); gtk_widget_show (dialog); } int main (int argc, char *argv[]) { GtkWidget *window; GtkWidget *vbox; GtkWidget *button; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Message Dialogs"); g_signal_connect (window, "destroy", gtk_main_quit, NULL); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_add (GTK_CONTAINER (window), vbox); button = gtk_button_new_with_label ("Confirmation dialog"); g_signal_connect (button, "clicked", G_CALLBACK (button_clicked_cb), window); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); gtk_widget_show_all (window); gtk_main (); return 0; } ./COPYING0000644000004100000410000001672714320114711012305 0ustar www-datawww-data GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. ./src/0000755000004100000410000000000014320114725012031 5ustar www-datawww-data./src/idobasicmenuitem.h0000644000004100000410000000464014320114711015522 0ustar www-datawww-data/** * Copyright 2013 Canonical Ltd. * * Authors: * Charles Kerr * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifndef __IDO_BASIC_MENU_ITEM_H__ #define __IDO_BASIC_MENU_ITEM_H__ #include G_BEGIN_DECLS #define IDO_TYPE_BASIC_MENU_ITEM (ido_basic_menu_item_get_type ()) #define IDO_BASIC_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IDO_TYPE_BASIC_MENU_ITEM, IdoBasicMenuItem)) #define IDO_IS_BASIC_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IDO_TYPE_BASIC_MENU_ITEM)) typedef struct _IdoBasicMenuItem IdoBasicMenuItem; typedef struct _IdoBasicMenuItemClass IdoBasicMenuItemClass; typedef struct _IdoBasicMenuItemPrivate IdoBasicMenuItemPrivate; struct _IdoBasicMenuItemClass { GtkMenuItemClass parent_class; }; /** * A simple menuitem that includes a right-justified secondary text. */ struct _IdoBasicMenuItem { /*< private >*/ GtkMenuItem parent; IdoBasicMenuItemPrivate * priv; }; GType ido_basic_menu_item_get_type (void) G_GNUC_CONST; GtkWidget * ido_basic_menu_item_new (void); void ido_basic_menu_item_set_icon (IdoBasicMenuItem * self, GIcon * icon); void ido_basic_menu_item_set_icon_from_file (IdoBasicMenuItem * self, const char * filename); void ido_basic_menu_item_set_text (IdoBasicMenuItem * self, const char * text); void ido_basic_menu_item_set_secondary_text (IdoBasicMenuItem * self, const char * text); GtkMenuItem * ido_basic_menu_item_new_from_model (GMenuItem * menuitem, GActionGroup * actions); G_END_DECLS #endif ./src/idoapplicationmenuitem.h0000644000004100000410000000277114320114711016747 0ustar www-datawww-data/* * Copyright 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * * Authors: * Lars Uebernickel */ #ifndef __IDO_APPLICATION_MENU_ITEM_H__ #define __IDO_APPLICATION_MENU_ITEM_H__ #include #define IDO_TYPE_APPLICATION_MENU_ITEM (ido_application_menu_item_get_type ()) #define IDO_APPLICATION_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IDO_TYPE_APPLICATION_MENU_ITEM, IdoApplicationMenuItem)) #define IS_IDO_APPLICATION_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IDO_TYPE_APPLICATION_MENU_ITEM)) typedef struct _IdoApplicationMenuItem IdoApplicationMenuItem; GType ido_application_menu_item_get_type (void); GtkMenuItem * ido_application_menu_item_new_from_model (GMenuItem *item, GActionGroup *actions); #endif ./src/idocalendarmenuitem.h0000644000004100000410000000716314320114711016215 0ustar www-datawww-data/* * Copyright 2010 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of either or both of the following licenses: * * 1) the GNU Lesser General Public License version 3, as published by the * Free Software Foundation; and/or * 2) the GNU Lesser General Public License version 2.1, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License version 3 and version 2.1 along with this program. If not, see * * * Authors: * Cody Russell */ #ifndef __IDO_CALENDAR_MENU_ITEM_H__ #define __IDO_CALENDAR_MENU_ITEM_H__ #include G_BEGIN_DECLS #define IDO_TYPE_CALENDAR_MENU_ITEM (ido_calendar_menu_item_get_type ()) #define IDO_CALENDAR_MENU_ITEM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), IDO_TYPE_CALENDAR_MENU_ITEM, IdoCalendarMenuItem)) #define IDO_CALENDAR_MENU_ITEM_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), IDO_TYPE_CALENDAR_MENU_ITEM, IdoCalendarMenuItemClass)) #define IDO_IS_CALENDAR_MENU_ITEM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), IDO_TYPE_CALENDAR_MENU_ITEM)) #define IDO_IS_CALENDAR_MENU_ITEM_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), IDO_TYPE_CALENDAR_MENU_ITEM)) #define IDO_CALENDAR_MENU_ITEM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), IDO_TYPE_CALENDAR_MENU_ITEM, IdoCalendarMenuItemClass)) typedef struct _IdoCalendarMenuItem IdoCalendarMenuItem; typedef struct _IdoCalendarMenuItemClass IdoCalendarMenuItemClass; typedef struct _IdoCalendarMenuItemPrivate IdoCalendarMenuItemPrivate; struct _IdoCalendarMenuItem { GtkMenuItem parent_instance; IdoCalendarMenuItemPrivate *priv; }; struct _IdoCalendarMenuItemClass { GtkMenuItemClass parent_class; }; GType ido_calendar_menu_item_get_type (void) G_GNUC_CONST; GtkWidget *ido_calendar_menu_item_new (void); GtkWidget *ido_calendar_menu_item_get_calendar (IdoCalendarMenuItem *menuitem); gboolean ido_calendar_menu_item_mark_day (IdoCalendarMenuItem *menuitem, guint day); gboolean ido_calendar_menu_item_unmark_day (IdoCalendarMenuItem *menuitem, guint day); void ido_calendar_menu_item_clear_marks (IdoCalendarMenuItem *menuitem); void ido_calendar_menu_item_set_display_options (IdoCalendarMenuItem *menuitem, GtkCalendarDisplayOptions flags); GtkCalendarDisplayOptions ido_calendar_menu_item_get_display_options (IdoCalendarMenuItem *menuitem); void ido_calendar_menu_item_get_date (IdoCalendarMenuItem *menuitem, guint *year, guint *month, guint *day); gboolean ido_calendar_menu_item_set_date (IdoCalendarMenuItem *menuitem, guint year, guint month, guint day); GtkMenuItem * ido_calendar_menu_item_new_from_model (GMenuItem * menuitem, GActionGroup * actions); G_END_DECLS #endif /* __IDO_CALENDAR_MENU_ITEM_H__ */ ./src/idotypebuiltins.c.template0000644000004100000410000000135614320114711017236 0ustar www-datawww-data/*** BEGIN file-header ***/ #include "idotypebuiltins.h" /*** END file-header ***/ /*** BEGIN file-production ***/ /* enumerations from "@filename@" */ #include "@filename@" /*** END file-production ***/ /*** BEGIN value-header ***/ GType @enum_name@_get_type(void) { static GType enum_type_id = 0; if (G_UNLIKELY (!enum_type_id)) { static const G@Type@Value values[] = { /*** END value-header ***/ /*** BEGIN value-production ***/ { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, /*** END value-production ***/ /*** BEGIN value-tail ***/ { 0, NULL, NULL } }; enum_type_id = g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); } return enum_type_id; } /*** END value-tail ***/ ./src/idoactionhelper.c0000644000004100000410000003374214320114711015352 0ustar www-datawww-data/* * Copyright 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * * Authors: * Lars Uebernickel */ #include "idoactionhelper.h" typedef GObjectClass IdoActionHelperClass; struct _IdoActionHelper { GObject parent; GtkWidget *widget; GActionGroup *actions; gchar *action_name; GVariant *action_target; guint idle_source_id; }; G_DEFINE_TYPE (IdoActionHelper, ido_action_helper, G_TYPE_OBJECT) enum { PROP_0, PROP_WIDGET, PROP_ACTION_GROUP, PROP_ACTION_NAME, PROP_ACTION_TARGET, NUM_PROPERTIES }; enum { ACTION_STATE_CHANGED, NUM_SIGNALS }; static GParamSpec *properties[NUM_PROPERTIES]; static guint signals[NUM_SIGNALS]; static void ido_action_helper_action_added (GActionGroup *actions, const gchar *action_name, gpointer user_data) { IdoActionHelper *helper = user_data; gboolean enabled; GVariant *state; if (!g_str_equal (action_name, helper->action_name)) return; if (g_action_group_query_action (actions, action_name, &enabled, NULL, NULL, NULL, &state)) { gtk_widget_set_sensitive (helper->widget, enabled); if (state) { g_signal_emit (helper, signals[ACTION_STATE_CHANGED], 0, state); g_variant_unref (state); } } else { gtk_widget_set_sensitive (helper->widget, FALSE); } } static void ido_action_helper_action_removed (GActionGroup *action_group, gchar *action_name, gpointer user_data) { IdoActionHelper *helper = user_data; if (g_str_equal (action_name, helper->action_name)) gtk_widget_set_sensitive (helper->widget, FALSE); } static void ido_action_helper_action_enabled_changed (GActionGroup *action_group, gchar *action_name, gboolean enabled, gpointer user_data) { IdoActionHelper *helper = user_data; if (g_str_equal (action_name, helper->action_name)) gtk_widget_set_sensitive (helper->widget, enabled); } static void ido_action_helper_action_state_changed (GActionGroup *action_group, gchar *action_name, GVariant *value, gpointer user_data) { IdoActionHelper *helper = user_data; if (g_str_equal (action_name, helper->action_name)) g_signal_emit (helper, signals[ACTION_STATE_CHANGED], 0, value); } static gboolean call_action_added (gpointer user_data) { IdoActionHelper *helper = user_data; ido_action_helper_action_added (helper->actions, helper->action_name, helper); helper->idle_source_id = 0; return G_SOURCE_REMOVE; } static void ido_action_helper_constructed (GObject *object) { IdoActionHelper *helper = IDO_ACTION_HELPER (object); g_signal_connect (helper->actions, "action-added", G_CALLBACK (ido_action_helper_action_added), helper); g_signal_connect (helper->actions, "action-removed", G_CALLBACK (ido_action_helper_action_removed), helper); g_signal_connect (helper->actions, "action-enabled-changed", G_CALLBACK (ido_action_helper_action_enabled_changed), helper); g_signal_connect (helper->actions, "action-state-changed", G_CALLBACK (ido_action_helper_action_state_changed), helper); if (g_action_group_has_action (helper->actions, helper->action_name)) { /* call action_added in an idle, so that we don't fire the * state-changed signal during construction (nobody could have * connected by then). */ helper->idle_source_id = g_idle_add (call_action_added, helper); } G_OBJECT_CLASS (ido_action_helper_parent_class)->constructed (object); } static void ido_action_helper_get_property (GObject *object, guint id, GValue *value, GParamSpec *pspec) { IdoActionHelper *helper = IDO_ACTION_HELPER (object); switch (id) { case PROP_WIDGET: g_value_set_object (value, helper->widget); break; case PROP_ACTION_GROUP: g_value_set_object (value, helper->actions); break; case PROP_ACTION_NAME: g_value_set_string (value, helper->action_name); break; case PROP_ACTION_TARGET: g_value_set_variant (value, helper->action_target); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, id, pspec); } } static void ido_action_helper_set_property (GObject *object, guint id, const GValue *value, GParamSpec *pspec) { IdoActionHelper *helper = IDO_ACTION_HELPER (object); switch (id) { case PROP_WIDGET: /* construct-only */ helper->widget = g_value_dup_object (value); break; case PROP_ACTION_GROUP: /* construct-only */ helper->actions = g_value_dup_object (value); break; case PROP_ACTION_NAME: /* construct-only */ helper->action_name = g_value_dup_string (value); break; case PROP_ACTION_TARGET: /* construct-only */ helper->action_target = g_value_dup_variant (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, id, pspec); } } static void ido_action_helper_finalize (GObject *object) { IdoActionHelper *helper = IDO_ACTION_HELPER (object); if (helper->idle_source_id) g_source_remove (helper->idle_source_id); g_object_unref (helper->widget); g_signal_handlers_disconnect_by_data (helper->actions, helper); g_object_unref (helper->actions); g_free (helper->action_name); if (helper->action_target) g_variant_unref (helper->action_target); G_OBJECT_CLASS (ido_action_helper_parent_class)->finalize (object); } static void ido_action_helper_class_init (IdoActionHelperClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); object_class->constructed = ido_action_helper_constructed; object_class->get_property = ido_action_helper_get_property; object_class->set_property = ido_action_helper_set_property; object_class->finalize = ido_action_helper_finalize; /** * IdoActionHelper::action-state-changed: * @helper: the #IdoActionHelper watching the action * @state: the new state of the action * * Emitted when the widget must be updated from the action's state, * which happens every time the action appears in the group and when * the action changes its state. */ signals[ACTION_STATE_CHANGED] = g_signal_new ("action-state-changed", IDO_TYPE_ACTION_HELPER, G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__VARIANT, G_TYPE_NONE, 1, G_TYPE_VARIANT); /** * IdoActionHelper:widget: * * The widget that is associated with this action helper. The action * helper updates the widget's "sensitive" property to reflect whether * the action #IdoActionHelper:action-name exists in * #IdoActionHelper:action-group. */ properties[PROP_WIDGET] = g_param_spec_object ("widget", "", "", GTK_TYPE_WIDGET, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * IdoActionHelper:action-group: * * The action group that eventually contains the action that * #IdoActionHelper:widget should be bound to. */ properties[PROP_ACTION_GROUP] = g_param_spec_object ("action-group", "", "", G_TYPE_ACTION_GROUP, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * IdoActionHelper:action-name: * * The name of the action in #IdoActionHelper:action-group that * should be bound to #IdoActionHelper:widget */ properties[PROP_ACTION_NAME] = g_param_spec_string ("action-name", "", "", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * IdoActionHelper:action-target: * * The target of #IdoActionHelper:widget. ido_action_helper_activate() * passes the target as parameter when activating the action. * * The handler of #IdoActionHelper:action-state-changed is responsible * for comparing this target with the action's state and updating the * #IdoActionHelper:widget appropriately. */ properties[PROP_ACTION_TARGET] = g_param_spec_variant ("action-target", "", "", G_VARIANT_TYPE_ANY, NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, NUM_PROPERTIES, properties); } static void ido_action_helper_init (IdoActionHelper *helper) { } /** * ido_action_helper_new: * @widget: a #GtkWidget * @action_group: a #GActionGroup * @action_name: the name of an action in @action_group * @target: the target of the action * * Creates a new #IdoActionHelper. This helper ties @widget to an action * (and a target), and performs some common tasks: * * @widget will be set to insensitive whenever @action_group does not * contain an action with the name @action_name, or the action with that * name is disabled. * * Also, the helper emits the "action-state-changed" signal whenever the * widget must be updated from the action's state. This includes once * when the action was added, and every time the action changes its * state. * * Returns: (transfer full): a new #IdoActionHelper */ IdoActionHelper * ido_action_helper_new (GtkWidget *widget, GActionGroup *action_group, const gchar *action_name, GVariant *target) { g_return_val_if_fail (widget != NULL, NULL); g_return_val_if_fail (action_group != NULL, NULL); g_return_val_if_fail (action_name != NULL, NULL); return g_object_new (IDO_TYPE_ACTION_HELPER, "widget", widget, "action-group", action_group, "action-name", action_name, "action-target", target, NULL); } /** * ido_action_helper_get_widget: * @helper: an #IdoActionHelper * * Returns: (transfer none): the #GtkWidget associated with @helper */ GtkWidget * ido_action_helper_get_widget (IdoActionHelper *helper) { g_return_val_if_fail (IDO_IS_ACTION_HELPER (helper), NULL); return helper->widget; } /** * ido_action_helper_get_action_target: * @helper: an #IdoActionHelper * * Returns: (transfer none): the action target that was set in * ido_action_helper_new() as a #GVariant */ GVariant * ido_action_helper_get_action_target (IdoActionHelper *helper) { g_return_val_if_fail (IDO_IS_ACTION_HELPER (helper), NULL); return helper->action_target; } /** * ido_action_helper_activate: * @helper: an #IdoActionHelper * * Activates the action that is associated with this helper. */ void ido_action_helper_activate (IdoActionHelper *helper) { g_return_if_fail (IDO_IS_ACTION_HELPER (helper)); if (helper->actions && helper->action_name) g_action_group_activate_action (helper->actions, helper->action_name, helper->action_target); } /** * ido_action_helper_activate_with_parameter: * @helper: an #IdoActionHelper * @parameter: a #GVariant containing the parameter * * Activates the action that is associated with this helper passing * @parameter instead the "target" associated with the menu item this * helper is bound to. */ void ido_action_helper_activate_with_parameter (IdoActionHelper *helper, GVariant *parameter) { g_return_if_fail (IDO_IS_ACTION_HELPER (helper)); g_return_if_fail (parameter != NULL); g_variant_ref_sink (parameter); if (helper->actions && helper->action_name) g_action_group_activate_action (helper->actions, helper->action_name, parameter); g_variant_unref (parameter); } /** * ido_action_helper_change_action_state: * @helper: an #IdoActionHelper * @state: the proposed new state of the action * * Requests changing the state of the action that is associated with * @helper to @state. * * If @state is floating, it is consumed. */ void ido_action_helper_change_action_state (IdoActionHelper *helper, GVariant *state) { g_return_if_fail (IDO_IS_ACTION_HELPER (helper)); g_return_if_fail (state != NULL); g_variant_ref_sink (state); if (helper->actions && helper->action_name) g_action_group_change_action_state (helper->actions, helper->action_name, state); g_variant_unref (state); } ./src/idoappointmentmenuitem.c0000644000004100000410000001130414320114711016765 0ustar www-datawww-data/* * Copyright 2013 Canonical Ltd. * * Authors: * Charles Kerr * Ted Gould * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "idoactionhelper.h" #include "idotimestampmenuitem.h" /* create a menu-sized pixbuf filled with specified color */ static GdkPixbuf * create_color_icon_pixbuf (const char * color_spec) { static int width = -1; static int height = -1; GdkPixbuf * pixbuf = NULL; if (width == -1) { gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height); width = CLAMP (width, 10, 30); height = CLAMP (height, 10, 30); } if (color_spec && *color_spec) { cairo_surface_t * surface; cairo_t * cr; GdkRGBA rgba; surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); cr = cairo_create (surface); if (gdk_rgba_parse (&rgba, color_spec)) gdk_cairo_set_source_rgba (cr, &rgba); cairo_paint (cr); cairo_set_source_rgba (cr, 0, 0, 0, 0.5); cairo_set_line_width (cr, 1); cairo_rectangle (cr, 0.5, 0.5, width-1, height-1); cairo_stroke (cr); pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, width, height); cairo_destroy (cr); cairo_surface_destroy (surface); } return pixbuf; } /** * ido_appointment_menu_item_new_from_model: * @menu_item: the corresponding menuitem * @actions: action group to tell when this GtkMenuItem is activated * * Creates a new IdoTimeStampMenuItem with properties initialized * appropriately for a com.canonical.indicator.alarm * * If the menuitem's 'action' attribute is set, trigger that action * in @actions when this IdoAppointmentMenuItem is activated. */ GtkMenuItem * ido_appointment_menu_item_new_from_model (GMenuItem * menu_item, GActionGroup * actions) { guint i; guint n; gint64 i64; gchar * str; IdoBasicMenuItem * ido_menu_item; GParameter parameters[8]; /* create the ido_menu_item */ n = 0; if (g_menu_item_get_attribute (menu_item, G_MENU_ATTRIBUTE_LABEL, "s", &str)) { GParameter p = { "text", G_VALUE_INIT }; g_value_init (&p.value, G_TYPE_STRING); g_value_take_string (&p.value, str); parameters[n++] = p; } if (g_menu_item_get_attribute (menu_item, "x-canonical-color", "s", &str)) { GParameter p = { "icon", G_VALUE_INIT }; g_value_init (&p.value, G_TYPE_OBJECT); g_value_take_object (&p.value, create_color_icon_pixbuf (str)); parameters[n++] = p; g_free (str); } if (g_menu_item_get_attribute (menu_item, "x-canonical-time-format", "s", &str)) { GParameter p = { "format", G_VALUE_INIT }; g_value_init (&p.value, G_TYPE_STRING); g_value_take_string (&p.value, str); parameters[n++] = p; } if (g_menu_item_get_attribute (menu_item, "x-canonical-time", "x", &i64)) { GParameter p = { "date-time", G_VALUE_INIT }; g_value_init (&p.value, G_TYPE_DATE_TIME); g_value_take_boxed (&p.value, g_date_time_new_from_unix_local (i64)); parameters[n++] = p; } g_assert (n <= G_N_ELEMENTS (parameters)); ido_menu_item = g_object_newv (IDO_TYPE_TIME_STAMP_MENU_ITEM, n, parameters); for (i=0; i. * * Authors: * Conor Curran * Lars Uebernickel */ #ifndef __IDO_PLAYBACK_MENU_ITEM_H__ #define __IDO_PLAYBACK_MENU_ITEM_H__ #include #define IDO_TYPE_PLAYBACK_MENU_ITEM (ido_playback_menu_item_get_type ()) #define IDO_PLAYBACK_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IDO_TYPE_PLAYBACK_MENU_ITEM, IdoPlaybackMenuItem)) #define IDO_IS_PLAYBACK_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IDO_TYPE_PLAYBACK_MENU_ITEM)) typedef struct _IdoPlaybackMenuItem IdoPlaybackMenuItem; GType ido_playback_menu_item_get_type (void); GtkMenuItem * ido_playback_menu_item_new_from_model (GMenuItem *item, GActionGroup *actions); #endif ./src/idoapplicationmenuitem.c0000644000004100000410000001340214320114711016733 0ustar www-datawww-data/* * Copyright 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * * Authors: * Lars Uebernickel */ #include "idoapplicationmenuitem.h" #include "idoactionhelper.h" typedef GtkMenuItemClass IdoApplicationMenuItemClass; struct _IdoApplicationMenuItem { GtkMenuItem parent; gboolean is_running; GtkWidget *icon; GtkWidget *label; }; G_DEFINE_TYPE (IdoApplicationMenuItem, ido_application_menu_item, GTK_TYPE_MENU_ITEM); static void ido_application_menu_item_constructed (GObject *object) { IdoApplicationMenuItem *item = IDO_APPLICATION_MENU_ITEM (object); GtkWidget *grid; gint icon_height; gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, NULL, &icon_height); item->icon = g_object_ref (gtk_image_new ()); gtk_image_set_pixel_size (GTK_IMAGE (item->icon), icon_height); gtk_widget_set_margin_right (item->icon, 6); item->label = g_object_ref (gtk_label_new ("")); grid = gtk_grid_new (); gtk_grid_attach (GTK_GRID (grid), item->icon, 0, 0, 1, 1); gtk_grid_attach (GTK_GRID (grid), item->label, 1, 0, 1, 1); gtk_container_add (GTK_CONTAINER (object), grid); gtk_widget_show_all (grid); G_OBJECT_CLASS (ido_application_menu_item_parent_class)->constructed (object); } static void ido_application_menu_item_dispose (GObject *object) { IdoApplicationMenuItem *self = IDO_APPLICATION_MENU_ITEM (object); g_clear_object (&self->icon); g_clear_object (&self->label); G_OBJECT_CLASS (ido_application_menu_item_parent_class)->dispose (object); } static gboolean ido_application_menu_item_draw (GtkWidget *widget, cairo_t *cr) { IdoApplicationMenuItem *item = IDO_APPLICATION_MENU_ITEM (widget); GTK_WIDGET_CLASS (ido_application_menu_item_parent_class)->draw (widget, cr); if (item->is_running) { const int arrow_width = 5; const double half_arrow_height = 4.5; GtkAllocation alloc; GdkRGBA color; double center; gtk_widget_get_allocation (widget, &alloc); gtk_style_context_get_color (gtk_widget_get_style_context (widget), gtk_widget_get_state_flags (widget), &color); gdk_cairo_set_source_rgba (cr, &color); center = alloc.height / 2 + 0.5; cairo_move_to (cr, 0, center - half_arrow_height); cairo_line_to (cr, 0, center + half_arrow_height); cairo_line_to (cr, arrow_width, center); cairo_close_path (cr); cairo_fill (cr); } return FALSE; } void ido_application_menu_item_class_init (IdoApplicationMenuItemClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->constructed = ido_application_menu_item_constructed; object_class->dispose = ido_application_menu_item_dispose; widget_class->draw = ido_application_menu_item_draw; } static void ido_application_menu_item_init (IdoApplicationMenuItem *self) { } static void ido_application_menu_item_set_label (IdoApplicationMenuItem *item, const gchar *label) { gtk_label_set_label (GTK_LABEL (item->label), label); } static void ido_application_menu_item_set_icon (IdoApplicationMenuItem *item, GIcon *icon) { gtk_image_set_from_gicon (GTK_IMAGE (item->icon), icon, GTK_ICON_SIZE_MENU); } static void ido_application_menu_item_state_changed (IdoActionHelper *helper, GVariant *state, gpointer user_data) { IdoApplicationMenuItem *item = user_data; item->is_running = g_variant_get_boolean (state); gtk_widget_queue_draw (GTK_WIDGET (item)); } GtkMenuItem * ido_application_menu_item_new_from_model (GMenuItem *menuitem, GActionGroup *actions) { GtkMenuItem *item; gchar *label; GVariant *serialized_icon; gchar *action; item = g_object_new (IDO_TYPE_APPLICATION_MENU_ITEM, NULL); if (g_menu_item_get_attribute (menuitem, "label", "s", &label)) { ido_application_menu_item_set_label (IDO_APPLICATION_MENU_ITEM (item), label); g_free (label); } serialized_icon = g_menu_item_get_attribute_value (menuitem, "icon", NULL); if (serialized_icon) { GIcon *icon; icon = g_icon_deserialize (serialized_icon); if (icon) { ido_application_menu_item_set_icon (IDO_APPLICATION_MENU_ITEM (item), icon); g_object_unref (icon); } g_variant_unref (serialized_icon); } if (g_menu_item_get_attribute (menuitem, "action", "s", &action)) { IdoActionHelper *helper; helper = ido_action_helper_new (GTK_WIDGET (item), actions, action, NULL); g_signal_connect (helper, "action-state-changed", G_CALLBACK (ido_application_menu_item_state_changed), item); g_signal_connect_object (item, "activate", G_CALLBACK (ido_action_helper_activate), helper, G_CONNECT_SWAPPED); g_signal_connect_swapped (item, "destroy", G_CALLBACK (g_object_unref), helper); g_free (action); } return item; } ./src/idoscalemenuitem.h0000644000004100000410000001116714320114711015532 0ustar www-datawww-data/* * Copyright 2010 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of either or both of the following licenses: * * 1) the GNU Lesser General Public License version 3, as published by the * Free Software Foundation; and/or * 2) the GNU Lesser General Public License version 2.1, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License version 3 and version 2.1 along with this program. If not, see * * * Authors: * Cody Russell */ #ifndef __IDO_SCALE_MENU_ITEM_H__ #define __IDO_SCALE_MENU_ITEM_H__ #include #include "idorange.h" G_BEGIN_DECLS #define IDO_TYPE_SCALE_MENU_ITEM (ido_scale_menu_item_get_type ()) #define IDO_SCALE_MENU_ITEM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), IDO_TYPE_SCALE_MENU_ITEM, IdoScaleMenuItem)) #define IDO_SCALE_MENU_ITEM_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), IDO_TYPE_SCALE_MENU_ITEM, IdoScaleMenuItemClass)) #define IDO_IS_SCALE_MENU_ITEM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), IDO_TYPE_SCALE_MENU_ITEM)) #define IDO_IS_SCALE_MENU_ITEM_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), IDO_TYPE_SCALE_MENU_ITEM)) #define IDO_SCALE_MENU_ITEM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), IDO_TYPE_SCALE_MENU_ITEM, IdoScaleMenuItemClass)) typedef enum { IDO_SCALE_MENU_ITEM_STYLE_NONE, IDO_SCALE_MENU_ITEM_STYLE_IMAGE, IDO_SCALE_MENU_ITEM_STYLE_LABEL } IdoScaleMenuItemStyle; typedef struct _IdoScaleMenuItem IdoScaleMenuItem; typedef struct _IdoScaleMenuItemClass IdoScaleMenuItemClass; typedef struct _IdoScaleMenuItemPrivate IdoScaleMenuItemPrivate; struct _IdoScaleMenuItem { GtkMenuItem parent_instance; IdoScaleMenuItemPrivate *priv; }; struct _IdoScaleMenuItemClass { GtkMenuItemClass parent_class; /* signal default handlers */ void (*primary_clicked)(IdoScaleMenuItem * menuitem); void (*secondary_clicked)(IdoScaleMenuItem * menuitem); }; GType ido_scale_menu_item_get_type (void) G_GNUC_CONST; GtkWidget *ido_scale_menu_item_new (const gchar *label, IdoRangeStyle size, GtkAdjustment *adjustment); GtkWidget *ido_scale_menu_item_new_with_range (const gchar *label, IdoRangeStyle size, gdouble value, gdouble min, gdouble max, gdouble step); GtkWidget *ido_scale_menu_item_get_scale (IdoScaleMenuItem *menuitem); IdoScaleMenuItemStyle ido_scale_menu_item_get_style (IdoScaleMenuItem *menuitem); void ido_scale_menu_item_set_style (IdoScaleMenuItem *menuitem, IdoScaleMenuItemStyle style); GtkWidget *ido_scale_menu_item_get_primary_image (IdoScaleMenuItem *menuitem); GtkWidget *ido_scale_menu_item_get_secondary_image (IdoScaleMenuItem *menuitem); const gchar *ido_scale_menu_item_get_primary_label (IdoScaleMenuItem *menuitem); void ido_scale_menu_item_set_primary_label (IdoScaleMenuItem *menuitem, const gchar *label); const gchar *ido_scale_menu_item_get_secondary_label (IdoScaleMenuItem *menuitem); void ido_scale_menu_item_set_secondary_label (IdoScaleMenuItem *menuitem, const gchar *label); void ido_scale_menu_item_primary_clicked (IdoScaleMenuItem *menuitem); void ido_scale_menu_item_secondary_clicked (IdoScaleMenuItem *menuitem); GtkMenuItem * ido_scale_menu_item_new_from_model (GMenuItem *menuitem, GActionGroup *actions); G_END_DECLS #endif /* __IDO_SCALE_MENU_ITEM_H__ */ ./src/idosourcemenuitem.h0000644000004100000410000000265014320114711015740 0ustar www-datawww-data/* * Copyright 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * * Authors: * Lars Uebernickel */ #ifndef __IDO_SOURCE_MENU_ITEM_H__ #define __IDO_SOURCE_MENU_ITEM_H__ #include #define IDO_TYPE_SOURCE_MENU_ITEM (ido_source_menu_item_get_type ()) #define IDO_SOURCE_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IDO_TYPE_SOURCE_MENU_ITEM, IdoSourceMenuItem)) #define IDO_IS_SOURCE_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IDO_TYPE_SOURCE_MENU_ITEM)) typedef struct _IdoSourceMenuItem IdoSourceMenuItem; GType ido_source_menu_item_get_type (void); GtkMenuItem * ido_source_menu_item_new_from_menu_model (GMenuItem *menuitem, GActionGroup *actions); #endif ./src/idoalarmmenuitem.c0000644000004100000410000000711314320114711015526 0ustar www-datawww-data/* * Copyright 2013 Canonical Ltd. * * Authors: * Charles Kerr * Ted Gould * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "idoactionhelper.h" #include "idotimestampmenuitem.h" /** * ido_alarm_menu_item_new_from_model: * @menu_item: the corresponding menuitem * @actions: action group to tell when this GtkMenuItem is activated * * Creates a new IdoTimeStampMenuItem with properties initialized * appropriately for a com.canonical.indicator.alarm * * If the menuitem's 'action' attribute is set, trigger that action * in @actions when this IdoAppointmentMenuItem is activated. */ GtkMenuItem * ido_alarm_menu_item_new_from_model (GMenuItem * menu_item, GActionGroup * actions) { guint i; guint n; gint64 i64; gchar * str; IdoBasicMenuItem * ido_menu_item; GParameter parameters[8]; /* create the ido_menu_item */ n = 0; if (g_menu_item_get_attribute (menu_item, G_MENU_ATTRIBUTE_LABEL, "s", &str)) { GParameter p = { "text", G_VALUE_INIT }; g_value_init (&p.value, G_TYPE_STRING); g_value_take_string (&p.value, str); parameters[n++] = p; } if (TRUE) { GParameter p = { "icon", G_VALUE_INIT }; g_value_init (&p.value, G_TYPE_OBJECT); g_value_take_object (&p.value, g_themed_icon_new_with_default_fallbacks ("alarm-symbolic")); parameters[n++] = p; } if (g_menu_item_get_attribute (menu_item, "x-canonical-time-format", "s", &str)) { GParameter p = { "format", G_VALUE_INIT }; g_value_init (&p.value, G_TYPE_STRING); g_value_take_string (&p.value, str); parameters[n++] = p; } if (g_menu_item_get_attribute (menu_item, "x-canonical-time", "x", &i64)) { GParameter p = { "date-time", G_VALUE_INIT }; g_value_init (&p.value, G_TYPE_DATE_TIME); g_value_take_boxed (&p.value, g_date_time_new_from_unix_local (i64)); parameters[n++] = p; } g_assert (n <= G_N_ELEMENTS (parameters)); ido_menu_item = g_object_newv (IDO_TYPE_TIME_STAMP_MENU_ITEM, n, parameters); for (i=0; i. * * Authors: * Lars Uebernickel */ #include /** * ido_init: * * Initializes ido. It has to be called after gtk_init(), but before any * other calls into ido are made. */ void ido_init (void) { GType ido_menu_item_factory_get_type (void); /* make sure this extension point is registered so that gtk calls it * when finding custom menu items */ g_type_ensure (ido_menu_item_factory_get_type ()); } ./src/idotypebuiltins.h.template0000644000004100000410000000100214320114711017227 0ustar www-datawww-data/*** BEGIN file-header ***/ #ifndef __IDO_ENUM_TYPES_H__ #define __IDO_ENUM_TYPES_H__ #include G_BEGIN_DECLS /*** END file-header ***/ /*** BEGIN file-production ***/ /* enumerations from "@filename@" */ /*** END file-production ***/ /*** BEGIN file-tail ***/ G_END_DECLS #endif /* !__IDO_ENUM_TYPES_H__ */ /*** END file-tail ***/ /*** BEGIN value-header ***/ GType @enum_name@_get_type (void) G_GNUC_CONST; #define IDO_TYPE_@ENUMSHORT@ (@enum_name@_get_type()) /*** END value-header ***/ ./src/idousermenuitem.c0000644000004100000410000004034114320114711015410 0ustar www-datawww-data/* Copyright 2011 Canonical Ltd. Authors: Conor Curran Mirco Müller Charles Kerr This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "idousermenuitem.h" #include "idoactionhelper.h" #define FALLBACK_ICON_NAME "avatar-default" enum { PROP_0, PROP_LABEL, PROP_ICON, PROP_IS_LOGGED_IN, PROP_IS_CURRENT_USER, PROP_LAST }; static GParamSpec *properties[PROP_LAST]; struct _IdoUserMenuItemPrivate { GtkWidget* user_image; GtkWidget* user_name; GtkWidget* container; GtkWidget* tick_icon; gboolean is_logged_in; gboolean is_current_user; gchar * label; GIcon * icon; }; G_DEFINE_TYPE (IdoUserMenuItem, ido_user_menu_item, GTK_TYPE_MENU_ITEM); /* Prototypes */ static gboolean ido_user_menu_item_primitive_draw_cb_gtk_3 (GtkWidget * image, cairo_t * cr, gpointer gself); /*** **** GObject virtual functions ***/ static void my_get_property (GObject * o, guint property_id, GValue * value, GParamSpec * pspec) { IdoUserMenuItem * self = IDO_USER_MENU_ITEM (o); switch (property_id) { case PROP_LABEL: g_value_set_string (value, self->priv->label); break; case PROP_ICON: g_value_set_object (value, self->priv->icon); break; case PROP_IS_LOGGED_IN: g_value_set_boolean (value, self->priv->is_logged_in); break; case PROP_IS_CURRENT_USER: g_value_set_boolean (value, self->priv->is_current_user); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); break; } } static void my_set_property (GObject * o, guint property_id, const GValue * value, GParamSpec * pspec) { IdoUserMenuItem * self = IDO_USER_MENU_ITEM (o); switch (property_id) { case PROP_LABEL: ido_user_menu_item_set_label (self, g_value_get_string (value)); break; case PROP_ICON: ido_user_menu_item_set_icon (self, g_value_get_object (value)); break; case PROP_IS_LOGGED_IN: ido_user_menu_item_set_logged_in (self, g_value_get_boolean (value)); break; case PROP_IS_CURRENT_USER: self->priv->is_current_user = g_value_get_boolean (value); gtk_widget_queue_draw (GTK_WIDGET(self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); break; } } static void my_dispose (GObject *object) { IdoUserMenuItem * self = IDO_USER_MENU_ITEM (object); g_clear_object (&self->priv->icon); G_OBJECT_CLASS (ido_user_menu_item_parent_class)->dispose (object); } static void my_finalize (GObject *object) { IdoUserMenuItem * self = IDO_USER_MENU_ITEM (object); g_free (self->priv->label); G_OBJECT_CLASS (ido_user_menu_item_parent_class)->finalize (object); } static void ido_user_menu_item_class_init (IdoUserMenuItemClass *klass) { GParamFlags prop_flags; GObjectClass * gobject_class = G_OBJECT_CLASS (klass); g_type_class_add_private (klass, sizeof (IdoUserMenuItemPrivate)); gobject_class->get_property = my_get_property; gobject_class->set_property = my_set_property; gobject_class->dispose = my_dispose; gobject_class->finalize = my_finalize; prop_flags = G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS; properties[PROP_LABEL] = g_param_spec_string ("label", "The user's name", "The name to display", "J. Random User", prop_flags); properties[PROP_ICON] = g_param_spec_object ("icon", "Icon", "The user's GIcon", G_TYPE_OBJECT, prop_flags); properties[PROP_IS_LOGGED_IN] = g_param_spec_boolean ("is-logged-in", "is logged in", "is user logged in?", FALSE, prop_flags); properties[PROP_IS_CURRENT_USER] = g_param_spec_boolean ("is-current-user", "is current user", "is user current?", FALSE, prop_flags); g_object_class_install_properties (gobject_class, PROP_LAST, properties); } static void ido_user_menu_item_init (IdoUserMenuItem *self) { IdoUserMenuItemPrivate * priv; self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, IDO_USER_MENU_ITEM_TYPE, IdoUserMenuItemPrivate); priv = self->priv; // Create the UI elements. priv->user_image = gtk_image_new (); gtk_image_set_from_icon_name (GTK_IMAGE (priv->user_image), FALLBACK_ICON_NAME, GTK_ICON_SIZE_MENU); priv->user_name = gtk_label_new (NULL); priv->container = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); priv->tick_icon = gtk_image_new_from_icon_name ("account-logged-in", GTK_ICON_SIZE_MENU); gtk_misc_set_alignment(GTK_MISC(priv->tick_icon), 1.0, 0.5); // Pack it together gtk_box_pack_start (GTK_BOX (priv->container), priv->user_image, FALSE, TRUE, 0); gtk_box_pack_start (GTK_BOX (priv->container), priv->user_name, FALSE, FALSE, 3); gtk_box_pack_end (GTK_BOX(priv->container), priv->tick_icon, FALSE, FALSE, 5); gtk_widget_show_all (priv->container); gtk_container_add (GTK_CONTAINER (self), priv->container); gtk_widget_show_all (priv->tick_icon); gtk_widget_set_no_show_all (priv->tick_icon, TRUE); gtk_widget_hide (priv->tick_icon); // Fetch the drawing context. g_signal_connect_after (GTK_WIDGET(self), "draw", G_CALLBACK(ido_user_menu_item_primitive_draw_cb_gtk_3), GTK_WIDGET(self)); } /*****************************************************************/ static gboolean ido_user_menu_item_primitive_draw_cb_gtk_3 (GtkWidget * widget, cairo_t * cr, gpointer user_data) { IdoUserMenuItemPrivate * priv; g_return_val_if_fail(IS_IDO_USER_MENU_ITEM(user_data), FALSE); priv = IDO_USER_MENU_ITEM(user_data)->priv; /* Draw dot only when user is the current user. */ if (priv->is_current_user) { GtkStyleContext * style_context; GtkStateFlags state_flags; GdkRGBA color; gdouble x, y; /* get the foreground color */ style_context = gtk_widget_get_style_context (widget); state_flags = gtk_widget_get_state_flags (widget); gtk_style_context_get_color (style_context, state_flags, &color); GtkAllocation allocation; gtk_widget_get_allocation (widget, &allocation); x = allocation.x + 13; y = allocation.height / 2; cairo_arc (cr, x, y, 3.0, 0.0, 2 * G_PI); gdk_cairo_set_source_rgba (cr, &color); cairo_fill (cr); } return FALSE; } /*** **** Avatar ***/ static gboolean ido_user_menu_item_set_icon_from_file_icon (IdoUserMenuItem *self, GFileIcon *icon) { GFile *file; gchar *path; gint width; gint height; GdkPixbuf *pixbuf; file = g_file_icon_get_file (G_FILE_ICON (icon)); path = g_file_get_path (file); /* width and height will always be set by this function */ gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (GTK_WIDGET (self)), GTK_ICON_SIZE_MENU, &width, &height); pixbuf = gdk_pixbuf_new_from_file_at_scale (path, width, height, TRUE, NULL); g_free (path); if (pixbuf) { gtk_image_set_from_pixbuf (GTK_IMAGE (self->priv->user_image), pixbuf); g_object_unref (pixbuf); return TRUE; } return FALSE; } /*** **** PUBLIC API ***/ void ido_user_menu_item_set_icon (IdoUserMenuItem * self, GIcon * icon) { IdoUserMenuItemPrivate * p = self->priv; if (p->icon == icon) return; g_clear_object (&p->icon); if (icon) p->icon = g_object_ref (icon); /* Avatars are always loaded from disk. Show the fallback when no icon * is set, the icon is not a file icon, or the file could not be * found. */ if (icon == NULL || !G_IS_FILE_ICON (icon) || !ido_user_menu_item_set_icon_from_file_icon (self, G_FILE_ICON (icon))) { gtk_image_set_from_icon_name (GTK_IMAGE (p->user_image), FALLBACK_ICON_NAME, GTK_ICON_SIZE_MENU); } } void ido_user_menu_item_set_icon_from_file (IdoUserMenuItem * self, const char * filename) { GFile * file = filename ? g_file_new_for_path (filename) : NULL; GIcon * icon = file ? g_file_icon_new (file) : NULL; ido_user_menu_item_set_icon (self, icon); g_clear_object (&icon); g_clear_object (&file); } void ido_user_menu_item_set_logged_in (IdoUserMenuItem * self, gboolean is_logged_in) { gtk_widget_set_visible (self->priv->tick_icon, is_logged_in); } void ido_user_menu_item_set_current_user (IdoUserMenuItem * self, gboolean is_current_user) { self->priv->is_current_user = is_current_user; gtk_widget_queue_draw (GTK_WIDGET (self)); } void ido_user_menu_item_set_label (IdoUserMenuItem * self, const char * label) { gtk_label_set_label (GTK_LABEL(self->priv->user_name), label); } GtkWidget* ido_user_menu_item_new (void) { return GTK_WIDGET (g_object_new (IDO_USER_MENU_ITEM_TYPE, NULL)); } /*** **** ***/ /* * This is a helper function for creating user menuitems for both * "indicator.user-menu-item" and "indicator.guest-menu-item", * since they only differ in how they use their action's state. */ static GtkMenuItem * user_menu_item_new_from_model (GMenuItem * menuitem, GActionGroup * actions, GCallback state_changed_callback) { guint i; guint n; IdoUserMenuItem * ido_user; gchar * str; gchar * action; GVariant * v; GParameter parameters[4]; /* create the ido_user */ n = 0; if (g_menu_item_get_attribute (menuitem, G_MENU_ATTRIBUTE_LABEL, "s", &str)) { GParameter p = { "label", G_VALUE_INIT }; g_value_init (&p.value, G_TYPE_STRING); g_value_take_string (&p.value, str); parameters[n++] = p; } if ((v = g_menu_item_get_attribute_value (menuitem, G_MENU_ATTRIBUTE_ICON, NULL))) { GParameter p = { "icon", G_VALUE_INIT }; GIcon * icon = g_icon_deserialize (v); g_value_init (&p.value, G_TYPE_OBJECT); g_value_take_object (&p.value, icon); g_variant_unref (v); parameters[n++] = p; } g_assert (n <= G_N_ELEMENTS (parameters)); ido_user = g_object_newv (IDO_USER_MENU_ITEM_TYPE, n, parameters); for (i=0; i * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifndef __IDO_ALARM_MENU_ITEM_H__ #define __IDO_ALARM_MENU_ITEM_H__ #include G_BEGIN_DECLS GtkMenuItem * ido_alarm_menu_item_new_from_model (GMenuItem * menuitem, GActionGroup * actions); G_END_DECLS #endif ./src/idolocationmenuitem.c0000644000004100000410000002301414320114711016240 0ustar www-datawww-data/* * Copyright 2013 Canonical Ltd. * * Authors: * Charles Kerr * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include /* strstr() */ #include #include "idoactionhelper.h" #include "idolocationmenuitem.h" enum { PROP_0, PROP_TIMEZONE, PROP_LAST }; static GParamSpec *properties[PROP_LAST]; struct _IdoLocationMenuItemPrivate { char * timezone; guint timestamp_timer; }; typedef IdoLocationMenuItemPrivate priv_t; G_DEFINE_TYPE (IdoLocationMenuItem, ido_location_menu_item, IDO_TYPE_TIME_STAMP_MENU_ITEM); /*** **** Timestamp Label ***/ static void update_timestamp (IdoLocationMenuItem * self) { GTimeZone * tz; GDateTime * date_time; tz = g_time_zone_new (self->priv->timezone); if (tz == NULL) tz = g_time_zone_new_local (); date_time = g_date_time_new_now (tz); ido_time_stamp_menu_item_set_date_time (IDO_TIME_STAMP_MENU_ITEM(self), date_time); g_date_time_unref (date_time); g_time_zone_unref (tz); } static void stop_timestamp_timer (IdoLocationMenuItem * self) { priv_t * p = self->priv; if (p->timestamp_timer != 0) { g_source_remove (p->timestamp_timer); p->timestamp_timer = 0; } } static void restart_timestamp_timer (IdoLocationMenuItem * self); static gboolean on_timestamp_timer (gpointer gself) { IdoLocationMenuItem * self = IDO_LOCATION_MENU_ITEM (gself); update_timestamp (self); restart_timestamp_timer (self); return G_SOURCE_REMOVE; } static guint calculate_seconds_until_next_minute (void) { guint seconds; GTimeSpan diff; GDateTime * now; GDateTime * next; GDateTime * start_of_next; now = g_date_time_new_now_local (); next = g_date_time_add_minutes (now, 1); start_of_next = g_date_time_new_local (g_date_time_get_year (next), g_date_time_get_month (next), g_date_time_get_day_of_month (next), g_date_time_get_hour (next), g_date_time_get_minute (next), 1); diff = g_date_time_difference (start_of_next, now); seconds = (diff + (G_TIME_SPAN_SECOND - 1)) / G_TIME_SPAN_SECOND; /* cleanup */ g_date_time_unref (start_of_next); g_date_time_unref (next); g_date_time_unref (now); return seconds; } static void restart_timestamp_timer (IdoLocationMenuItem * self) { const char * fmt = ido_time_stamp_menu_item_get_format (IDO_TIME_STAMP_MENU_ITEM (self)); gboolean timestamp_shows_seconds; int interval_sec; stop_timestamp_timer (self); timestamp_shows_seconds = fmt && (strstr(fmt,"%s") || strstr(fmt,"%S") || strstr(fmt,"%T") || strstr(fmt,"%X") || strstr(fmt,"%c")); if (timestamp_shows_seconds) interval_sec = 1; else interval_sec = calculate_seconds_until_next_minute(); self->priv->timestamp_timer = g_timeout_add_seconds (interval_sec, on_timestamp_timer, self); } /*** **** GObject Virtual Functions ***/ static void my_get_property (GObject * o, guint property_id, GValue * value, GParamSpec * pspec) { IdoLocationMenuItem * self = IDO_LOCATION_MENU_ITEM (o); priv_t * p = self->priv; switch (property_id) { case PROP_TIMEZONE: g_value_set_string (value, p->timezone); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); break; } } static void my_set_property (GObject * o, guint property_id, const GValue * value, GParamSpec * pspec) { IdoLocationMenuItem * self = IDO_LOCATION_MENU_ITEM (o); switch (property_id) { case PROP_TIMEZONE: ido_location_menu_item_set_timezone (self, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); break; } } static void my_dispose (GObject * object) { stop_timestamp_timer (IDO_LOCATION_MENU_ITEM (object)); G_OBJECT_CLASS (ido_location_menu_item_parent_class)->dispose (object); } static void my_finalize (GObject * object) { IdoLocationMenuItem * self = IDO_LOCATION_MENU_ITEM (object); g_free (self->priv->timezone); G_OBJECT_CLASS (ido_location_menu_item_parent_class)->finalize (object); } /*** **** Instantiation ***/ static void ido_location_menu_item_class_init (IdoLocationMenuItemClass *klass) { GObjectClass * gobject_class = G_OBJECT_CLASS (klass); g_type_class_add_private (klass, sizeof (IdoLocationMenuItemPrivate)); gobject_class->get_property = my_get_property; gobject_class->set_property = my_set_property; gobject_class->dispose = my_dispose; gobject_class->finalize = my_finalize; properties[PROP_TIMEZONE] = g_param_spec_string ( "timezone", "timezone identifier", "string used to identify a timezone; eg, 'America/Chicago'", NULL, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (gobject_class, PROP_LAST, properties); } static void ido_location_menu_item_init (IdoLocationMenuItem *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, IDO_LOCATION_MENU_ITEM_TYPE, IdoLocationMenuItemPrivate); /* Update the timer whenever the format string changes because it determines whether we update once per second or per minute */ g_signal_connect (self, "notify::format", G_CALLBACK(restart_timestamp_timer), NULL); } /*** **** Public API ***/ /* create a new IdoLocationMenuItemType */ GtkWidget * ido_location_menu_item_new (void) { return GTK_WIDGET (g_object_new (IDO_LOCATION_MENU_ITEM_TYPE, NULL)); } /** * ido_location_menu_item_set_timezone: * @timezone: timezone identifier (eg: "America/Chicago") * * Set this location's timezone. This will be used to show the location's * current time in menuitem's right-justified secondary label. */ void ido_location_menu_item_set_timezone (IdoLocationMenuItem * self, const char * timezone) { priv_t * p; g_return_if_fail (IDO_IS_LOCATION_MENU_ITEM (self)); p = self->priv; g_free (p->timezone); p->timezone = g_strdup (timezone); update_timestamp (self); } /** * ido_location_menu_item_new_from_model: * @menu_item: the corresponding menuitem * @actions: action group to tell when this GtkMenuItem is activated * * Creates a new IdoLocationMenuItem with properties initialized from * the menuitem's attributes. * * If the menuitem's 'action' attribute is set, trigger that action * in @actions when this IdoLocationMenuItem is activated. */ GtkMenuItem * ido_location_menu_item_new_from_model (GMenuItem * menu_item, GActionGroup * actions) { guint i; guint n; gchar * str; IdoLocationMenuItem * ido_location; GParameter parameters[4]; /* create the ido_location */ n = 0; if (g_menu_item_get_attribute (menu_item, "label", "s", &str)) { GParameter p = { "text", G_VALUE_INIT }; g_value_init (&p.value, G_TYPE_STRING); g_value_take_string (&p.value, str); parameters[n++] = p; } if (g_menu_item_get_attribute (menu_item, "x-canonical-timezone", "s", &str)) { GParameter p = { "timezone", G_VALUE_INIT }; g_value_init (&p.value, G_TYPE_STRING); g_value_take_string (&p.value, str); parameters[n++] = p; } if (g_menu_item_get_attribute (menu_item, "x-canonical-time-format", "s", &str)) { GParameter p = { "format", G_VALUE_INIT }; g_value_init (&p.value, G_TYPE_STRING); g_value_take_string (&p.value, str); parameters[n++] = p; } g_assert (n <= G_N_ELEMENTS (parameters)); ido_location = g_object_newv (IDO_LOCATION_MENU_ITEM_TYPE, n, parameters); for (i=0; i. * * Authors: * Lars Uebernickel */ #include "idosourcemenuitem.h" #include #include "idodetaillabel.h" #include "idoactionhelper.h" typedef GtkMenuItemClass IdoSourceMenuItemClass; struct _IdoSourceMenuItem { GtkMenuItem parent; GtkWidget *icon; GtkWidget *label; GtkWidget *detail; gint64 time; guint timer_id; }; G_DEFINE_TYPE (IdoSourceMenuItem, ido_source_menu_item, GTK_TYPE_MENU_ITEM); static void ido_source_menu_item_constructed (GObject *object) { IdoSourceMenuItem *item = IDO_SOURCE_MENU_ITEM (object); GtkWidget *grid; gint icon_width; gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, NULL); item->icon = g_object_ref (gtk_image_new ()); gtk_widget_set_margin_left (item->icon, icon_width); gtk_widget_set_margin_right (item->icon, 6); item->label = g_object_ref (gtk_label_new ("")); gtk_label_set_max_width_chars (GTK_LABEL (item->label), 40); gtk_label_set_ellipsize (GTK_LABEL (item->label), PANGO_ELLIPSIZE_END); gtk_misc_set_alignment (GTK_MISC (item->label), 0.0, 0.5); item->detail = g_object_ref (ido_detail_label_new ("")); gtk_widget_set_halign (item->detail, GTK_ALIGN_END); gtk_widget_set_hexpand (item->detail, TRUE); gtk_style_context_add_class (gtk_widget_get_style_context (item->detail), "accelerator"); grid = gtk_grid_new (); gtk_grid_attach (GTK_GRID (grid), item->icon, 0, 0, 1, 1); gtk_grid_attach (GTK_GRID (grid), item->label, 1, 0, 1, 1); gtk_grid_attach (GTK_GRID (grid), item->detail, 2, 0, 1, 1); gtk_container_add (GTK_CONTAINER (object), grid); gtk_widget_show_all (grid); G_OBJECT_CLASS (ido_source_menu_item_parent_class)->constructed (object); } static gchar * ido_source_menu_item_time_span_string (gint64 timestamp) { gchar *str; gint64 span; gint hours; gint minutes; span = MAX (g_get_real_time () - timestamp, 0) / G_USEC_PER_SEC; hours = span / 3600; minutes = (span / 60) % 60; if (hours == 0) { /* TRANSLATORS: number of minutes that have passed */ str = g_strdup_printf (ngettext ("%d min", "%d min", minutes), minutes); } else { /* TRANSLATORS: number of hours that have passed */ str = g_strdup_printf (ngettext ("%d h", "%d h", hours), hours); } return str; } static void ido_source_menu_item_set_detail_time (IdoSourceMenuItem *self, gint64 time) { gchar *str; self->time = time; str = ido_source_menu_item_time_span_string (self->time); ido_detail_label_set_text (IDO_DETAIL_LABEL (self->detail), str); g_free (str); } static gboolean ido_source_menu_item_update_time (gpointer data) { IdoSourceMenuItem *self = data; ido_source_menu_item_set_detail_time (self, self->time); return TRUE; } static void ido_source_menu_item_dispose (GObject *object) { IdoSourceMenuItem *self = IDO_SOURCE_MENU_ITEM (object); if (self->timer_id != 0) { g_source_remove (self->timer_id); self->timer_id = 0; } g_clear_object (&self->icon); g_clear_object (&self->label); g_clear_object (&self->detail); G_OBJECT_CLASS (ido_source_menu_item_parent_class)->dispose (object); } static void ido_source_menu_item_class_init (IdoSourceMenuItemClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructed = ido_source_menu_item_constructed; object_class->dispose = ido_source_menu_item_dispose; } static void ido_source_menu_item_init (IdoSourceMenuItem *self) { } static void ido_source_menu_item_set_label (IdoSourceMenuItem *item, const gchar *label) { gtk_label_set_label (GTK_LABEL (item->label), label ? label : ""); } static void ido_source_menu_item_set_icon (IdoSourceMenuItem *item, GIcon *icon) { if (icon) gtk_image_set_from_gicon (GTK_IMAGE (item->icon), icon, GTK_ICON_SIZE_MENU); else gtk_image_clear (GTK_IMAGE (item->icon)); } static void ido_source_menu_item_activate (GtkMenuItem *item, gpointer user_data) { IdoActionHelper *helper = user_data; /* The parameter signifies whether this source was activated (TRUE) or * dismissed (FALSE). Since there's no UI to dismiss a gtkmenuitem, * this always passes TRUE. */ ido_action_helper_activate_with_parameter (helper, g_variant_new_boolean (TRUE)); } static void ido_source_menu_item_state_changed (IdoActionHelper *helper, GVariant *state, gpointer user_data) { IdoSourceMenuItem *item = user_data; guint32 count; gint64 time; const gchar *str; if (item->timer_id != 0) { g_source_remove (item->timer_id); item->timer_id = 0; } g_return_if_fail (g_variant_is_of_type (state, G_VARIANT_TYPE ("(uxsb)"))); g_variant_get (state, "(ux&sb)", &count, &time, &str, NULL); if (count != 0) ido_detail_label_set_count (IDO_DETAIL_LABEL (item->detail), count); else if (time != 0) { ido_source_menu_item_set_detail_time (item, time); item->timer_id = g_timeout_add_seconds (59, ido_source_menu_item_update_time, item); } else if (str != NULL && *str) ido_detail_label_set_text (IDO_DETAIL_LABEL (item->detail), str); } GtkMenuItem * ido_source_menu_item_new_from_menu_model (GMenuItem *menuitem, GActionGroup *actions) { GtkMenuItem *item; GVariant *serialized_icon; GIcon *icon = NULL; gchar *label; gchar *action = NULL; item = g_object_new (IDO_TYPE_SOURCE_MENU_ITEM, NULL); if (g_menu_item_get_attribute (menuitem, "label", "s", &label)) { ido_source_menu_item_set_label (IDO_SOURCE_MENU_ITEM (item), label); g_free (label); } serialized_icon = g_menu_item_get_attribute_value (menuitem, "icon", NULL); if (serialized_icon) { icon = g_icon_deserialize (serialized_icon); g_variant_unref (serialized_icon); } ido_source_menu_item_set_icon (IDO_SOURCE_MENU_ITEM (item), icon); if (g_menu_item_get_attribute (menuitem, "action", "s", &action)) { IdoActionHelper *helper; helper = ido_action_helper_new (GTK_WIDGET (item), actions, action, NULL); g_signal_connect (helper, "action-state-changed", G_CALLBACK (ido_source_menu_item_state_changed), item); g_signal_connect_object (item, "activate", G_CALLBACK (ido_source_menu_item_activate), helper, 0); g_signal_connect_swapped (item, "destroy", G_CALLBACK (g_object_unref), helper); g_free (action); } if (icon) g_object_unref (icon); return item; } ./src/idomediaplayermenuitem.c0000644000004100000410000003010614320114725016731 0ustar www-datawww-data/* * Copyright 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * * Authors: * Conor Curran * Mirco Müller * Lars Uebernickel */ #include "config.h" #include "idomediaplayermenuitem.h" #include "idoactionhelper.h" #define ALBUM_ART_SIZE 60 typedef GtkMenuItemClass IdoMediaPlayerMenuItemClass; struct _IdoMediaPlayerMenuItem { GtkMenuItem parent; GCancellable *cancellable; GtkWidget* player_label; GtkWidget* player_icon; GtkWidget* metadata_widget; GtkWidget* album_art; GtkWidget* artist_label; GtkWidget* piece_label; GtkWidget* container_label; gboolean running; }; G_DEFINE_TYPE (IdoMediaPlayerMenuItem, ido_media_player_menu_item, GTK_TYPE_MENU_ITEM); static void ido_media_player_menu_item_dispose (GObject *object) { IdoMediaPlayerMenuItem *self = IDO_MEDIA_PLAYER_MENU_ITEM (object); if (self->cancellable) { g_cancellable_cancel (self->cancellable); g_clear_object (&self->cancellable); } G_OBJECT_CLASS (ido_media_player_menu_item_parent_class)->dispose (object); } static gboolean ido_media_player_menu_item_draw (GtkWidget *widget, cairo_t *cr) { IdoMediaPlayerMenuItem *self = IDO_MEDIA_PLAYER_MENU_ITEM (widget); GTK_WIDGET_CLASS (ido_media_player_menu_item_parent_class)->draw (widget, cr); /* draw a triangle next to the application name if the app is running */ if (self->running) { const int arrow_width = 5; const int half_arrow_height = 4; GdkRGBA color; GtkAllocation allocation; GtkAllocation label_allocation; int x; int y; gtk_style_context_get_color (gtk_widget_get_style_context (widget), gtk_widget_get_state (widget), &color); gtk_widget_get_allocation (widget, &allocation); gtk_widget_get_allocation (self->player_label, &label_allocation); x = allocation.x; y = label_allocation.y - allocation.y + label_allocation.height / 2; cairo_move_to (cr, x, y - half_arrow_height); cairo_line_to (cr, x, y + half_arrow_height); cairo_line_to (cr, x + arrow_width, y); cairo_close_path (cr); gdk_cairo_set_source_rgba (cr, &color); cairo_fill (cr); } return FALSE; } static void ido_media_player_menu_item_class_init (IdoMediaPlayerMenuItemClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = ido_media_player_menu_item_dispose; widget_class->draw = ido_media_player_menu_item_draw; } static GtkWidget * track_info_label_new () { GtkWidget *label; label = gtk_label_new (NULL); gtk_label_set_width_chars (GTK_LABEL (label), 25); gtk_label_set_max_width_chars (GTK_LABEL (label), 25); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_widget_set_halign (label, GTK_ALIGN_START); gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_MIDDLE); return label; } static void ido_media_player_menu_item_init (IdoMediaPlayerMenuItem *self) { GtkWidget *grid; self->cancellable = g_cancellable_new (); self->player_icon = gtk_image_new(); gtk_widget_set_margin_right (self->player_icon, 6); gtk_widget_set_halign (self->player_icon, GTK_ALIGN_START); self->player_label = gtk_label_new (NULL); gtk_widget_set_halign (self->player_label, GTK_ALIGN_START); gtk_widget_set_hexpand (self->player_label, TRUE); self->album_art = gtk_image_new(); gtk_widget_set_size_request (self->album_art, ALBUM_ART_SIZE, ALBUM_ART_SIZE); gtk_widget_set_margin_right (self->album_art, 8); self->artist_label = track_info_label_new (); self->piece_label = track_info_label_new (); self->container_label = track_info_label_new (); gtk_widget_set_vexpand (self->container_label, TRUE); gtk_widget_set_valign (self->container_label, GTK_ALIGN_START); self->metadata_widget = gtk_grid_new (); gtk_grid_attach (GTK_GRID (self->metadata_widget), self->album_art, 0, 0, 1, 4); gtk_grid_attach (GTK_GRID (self->metadata_widget), self->piece_label, 1, 0, 1, 1); gtk_grid_attach (GTK_GRID (self->metadata_widget), self->artist_label, 1, 1, 1, 1); gtk_grid_attach (GTK_GRID (self->metadata_widget), self->container_label, 1, 2, 1, 1); grid = gtk_grid_new (); gtk_grid_set_row_spacing (GTK_GRID (grid), 8); gtk_grid_attach (GTK_GRID (grid), self->player_icon, 0, 0, 1, 1); gtk_grid_attach (GTK_GRID (grid), self->player_label, 1, 0, 1, 1); gtk_grid_attach (GTK_GRID (grid), self->metadata_widget, 0, 1, 2, 1); gtk_container_add (GTK_CONTAINER (self), grid); gtk_widget_show_all (grid); /* hide metadata by defalut (player is not running) */ gtk_widget_hide (self->metadata_widget); } static void ido_media_player_menu_item_set_player_name (IdoMediaPlayerMenuItem *self, const gchar *name) { g_return_if_fail (IDO_IS_MEDIA_PLAYER_MENU_ITEM (self)); gtk_label_set_label (GTK_LABEL (self->player_label), name); } static void ido_media_player_menu_item_set_player_icon (IdoMediaPlayerMenuItem *self, GIcon *icon) { g_return_if_fail (IDO_IS_MEDIA_PLAYER_MENU_ITEM (self)); gtk_image_set_from_gicon (GTK_IMAGE (self->player_icon), icon, GTK_ICON_SIZE_MENU); } static void ido_media_player_menu_item_set_is_running (IdoMediaPlayerMenuItem *self, gboolean running) { g_return_if_fail (IDO_IS_MEDIA_PLAYER_MENU_ITEM (self)); if (self->running != running) { self->running = running; gtk_widget_queue_draw (GTK_WIDGET (self)); } } static void album_art_received (GObject *object, GAsyncResult *result, gpointer user_data) { IdoMediaPlayerMenuItem *self = user_data; GdkPixbuf *pixbuf; GError *error = NULL; pixbuf = gdk_pixbuf_new_from_stream_finish (result, &error); if (pixbuf == NULL) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) g_warning ("unable to fetch album art: %s", error->message); g_error_free (error); return; } gtk_image_set_from_pixbuf (GTK_IMAGE (self->album_art), pixbuf); g_object_unref (pixbuf); } static void album_art_file_opened (GObject *object, GAsyncResult *result, gpointer user_data) { IdoMediaPlayerMenuItem *self = user_data; GFileInputStream *input; GError *error = NULL; input = g_file_read_finish (G_FILE (object), result, &error); if (input == NULL) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) g_warning ("unable to fetch album art: %s", error->message); g_error_free (error); return; } gdk_pixbuf_new_from_stream_at_scale_async (G_INPUT_STREAM (input), ALBUM_ART_SIZE, ALBUM_ART_SIZE, TRUE, self->cancellable, album_art_received, self); g_object_unref (input); } static void ido_media_player_menu_item_set_album_art (IdoMediaPlayerMenuItem *self, const gchar *url) { GFile *file; g_return_if_fail (IDO_IS_MEDIA_PLAYER_MENU_ITEM (self)); gtk_image_clear (GTK_IMAGE (self->album_art)); if (url == NULL || *url == '\0') return; file = g_file_new_for_uri (url); g_file_read_async (file, G_PRIORITY_DEFAULT, self->cancellable, album_art_file_opened, self); g_object_unref (file); } static void gtk_label_set_markup_printf_escaped (GtkLabel *label, const gchar *format, ...) { va_list args; gchar *str; va_start (args, format); str = g_markup_vprintf_escaped (format, args); gtk_label_set_markup (label, str); va_end (args); g_free (str); } static void ido_media_player_menu_item_set_metadata (IdoMediaPlayerMenuItem *self, const gchar *title, const gchar *artist, const gchar *album, const gchar *art_url) { g_return_if_fail (IDO_IS_MEDIA_PLAYER_MENU_ITEM (self)); /* hide if there's no metadata */ if (title == NULL || *title == '\0') { gtk_label_set_label (GTK_LABEL (self->piece_label), NULL); gtk_label_set_label (GTK_LABEL (self->artist_label), NULL); gtk_label_set_label (GTK_LABEL (self->container_label), NULL); ido_media_player_menu_item_set_album_art (self, NULL); gtk_widget_hide (self->metadata_widget); } else { gtk_label_set_markup_printf_escaped (GTK_LABEL (self->piece_label), "%s", title); gtk_label_set_markup_printf_escaped (GTK_LABEL (self->artist_label), "%s", artist); gtk_label_set_markup_printf_escaped (GTK_LABEL (self->container_label), "%s", album); ido_media_player_menu_item_set_album_art (self, art_url); gtk_widget_show (self->metadata_widget); } } static void ido_media_player_menu_item_state_changed (IdoActionHelper *helper, GVariant *state, gpointer user_data) { IdoMediaPlayerMenuItem *widget; gboolean running = FALSE; const gchar *title = NULL; const gchar *artist = NULL; const gchar *album = NULL; const gchar *art_url = NULL; g_variant_lookup (state, "running", "b", &running); g_variant_lookup (state, "title", "&s", &title); g_variant_lookup (state, "artist", "&s", &artist); g_variant_lookup (state, "album", "&s", &album); g_variant_lookup (state, "art-url", "&s", &art_url); widget = IDO_MEDIA_PLAYER_MENU_ITEM (ido_action_helper_get_widget (helper)); ido_media_player_menu_item_set_is_running (widget, running); ido_media_player_menu_item_set_metadata (widget, title, artist, album, art_url); } GtkMenuItem * ido_media_player_menu_item_new_from_model (GMenuItem *menuitem, GActionGroup *actions) { GtkMenuItem *widget; gchar *label; gchar *action; GVariant *v; widget = g_object_new (IDO_TYPE_MEDIA_PLAYER_MENU_ITEM, NULL); if (g_menu_item_get_attribute (menuitem, "label", "s", &label)) { ido_media_player_menu_item_set_player_name (IDO_MEDIA_PLAYER_MENU_ITEM (widget), label); g_free (label); } if ((v = g_menu_item_get_attribute_value (menuitem, "icon", NULL))) { GIcon *icon; icon = g_icon_deserialize (v); if (icon) { ido_media_player_menu_item_set_player_icon (IDO_MEDIA_PLAYER_MENU_ITEM (widget), icon); g_object_unref (icon); } g_variant_unref (v); } if (g_menu_item_get_attribute (menuitem, "action", "s", &action)) { IdoActionHelper *helper; helper = ido_action_helper_new (GTK_WIDGET (widget), actions, action, NULL); g_signal_connect (helper, "action-state-changed", G_CALLBACK (ido_media_player_menu_item_state_changed), NULL); g_signal_connect_object (widget, "activate", G_CALLBACK (ido_action_helper_activate), helper, G_CONNECT_SWAPPED); g_signal_connect_swapped (widget, "destroy", G_CALLBACK (g_object_unref), helper); g_free (action); } return widget; } ./src/idorange.c0000644000004100000410000001416314320114711013765 0ustar www-datawww-data/* * Copyright 2010 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of either or both of the following licenses: * * 1) the GNU Lesser General Public License version 3, as published by the * Free Software Foundation; and/or * 2) the GNU Lesser General Public License version 2.1, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License version 3 and version 2.1 along with this program. If not, see * * * Authors: * Cody Russell */ #include "idorange.h" #include "idotypebuiltins.h" #include "config.h" struct _IdoRangePrivate { IdoRangeStyle style; }; static void ido_range_constructed (GObject *object); static void ido_range_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void ido_range_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); #define IDO_RANGE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), IDO_TYPE_RANGE, IdoRangePrivate)) G_DEFINE_TYPE (IdoRange, ido_range, GTK_TYPE_SCALE) enum { PROP_0, PROP_STYLE }; static void ido_range_class_init (IdoRangeClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); gobject_class->constructed = ido_range_constructed; gobject_class->set_property = ido_range_set_property; gobject_class->get_property = ido_range_get_property; g_object_class_install_property (gobject_class, PROP_STYLE, g_param_spec_enum ("range-style", "Range style", "The style of the range", IDO_TYPE_RANGE_STYLE, IDO_RANGE_STYLE_SMALL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); gtk_widget_class_install_style_property (widget_class, g_param_spec_int ("knob-width", "The knob width", "The knob width", G_MININT, G_MAXINT, 8, G_PARAM_READABLE)); gtk_widget_class_install_style_property (widget_class, g_param_spec_int ("knob-height", "The knob height", "The knob height", G_MININT, G_MAXINT, 8, G_PARAM_READABLE)); g_type_class_add_private (class, sizeof (IdoRangePrivate)); } static void ido_range_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { IdoRangePrivate *priv = IDO_RANGE (object)->priv; switch (prop_id) { case PROP_STYLE: g_value_set_enum (value, priv->style); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void ido_range_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { IdoRangePrivate *priv = IDO_RANGE (object)->priv; switch (prop_id) { case PROP_STYLE: priv->style = g_value_get_enum (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void ido_range_constructed (GObject *object) { IdoRange *range = IDO_RANGE (object); IdoRangeStyle style; char buf[1024]; g_object_get (range, "range-style", &style, NULL); g_snprintf (buf, sizeof (buf), "idorange-%p", range); gtk_widget_set_name (GTK_WIDGET (range), buf); if (style == IDO_RANGE_STYLE_SMALL) { gint width, height; gtk_widget_style_get (GTK_WIDGET (range), "knob-width", &width, "knob-height", &height, NULL); } gtk_range_set_slider_size_fixed (GTK_RANGE (range), TRUE); G_OBJECT_CLASS (ido_range_parent_class)->constructed (object); } static void ido_range_init (IdoRange *range) { range->priv = IDO_RANGE_GET_PRIVATE (range); } /** * ido_range_new: * @adj: A #GtkAdjustment providing the range values * @style: The range style * * Creates a new #IdoRange widget. * * Return Value: A new #IdoRange **/ GtkWidget * ido_range_new (GObject *adj, IdoRangeStyle style) { g_return_val_if_fail (GTK_IS_ADJUSTMENT (adj), NULL); return g_object_new (IDO_TYPE_RANGE, "orientation", GTK_ORIENTATION_HORIZONTAL, "adjustment", adj, "range-style", style, NULL); } ./src/idocalendarmenuitem.c0000644000004100000410000005431014320114711016204 0ustar www-datawww-data/* * Copyright 2010 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of either or both of the following licenses: * * 1) the GNU Lesser General Public License version 3, as published by the * Free Software Foundation; and/or * 2) the GNU Lesser General Public License version 2.1, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License version 3 and version 2.1 along with this program. If not, see * * * Authors: * Cody Russell */ #include #include "idoactionhelper.h" #include "idocalendarmenuitem.h" #include "config.h" static void ido_calendar_menu_item_finalize (GObject *item); static void ido_calendar_menu_item_select (GtkMenuItem *item); static void ido_calendar_menu_item_deselect (GtkMenuItem *item); static gboolean ido_calendar_menu_item_button_release (GtkWidget *widget, GdkEventButton *event); static gboolean ido_calendar_menu_item_button_press (GtkWidget *widget, GdkEventButton *event); static gboolean ido_calendar_menu_item_key_press (GtkWidget *widget, GdkEventKey *event, gpointer data); static void ido_calendar_menu_item_send_focus_change (GtkWidget *widget, gboolean in); static void calendar_realized_cb (GtkWidget *widget, IdoCalendarMenuItem *item); static void calendar_move_focus_cb (GtkWidget *widget, GtkDirectionType direction, IdoCalendarMenuItem *item); static void calendar_month_changed_cb (GtkWidget *widget, gpointer user_data); static void calendar_day_selected_double_click_cb (GtkWidget *widget, gpointer user_data); static void calendar_day_selected_cb (GtkWidget *widget, gpointer user_data); struct _IdoCalendarMenuItemPrivate { GtkWidget *box; GtkWidget *calendar; GtkWidget *parent; gboolean selected; }; G_DEFINE_TYPE (IdoCalendarMenuItem, ido_calendar_menu_item, GTK_TYPE_MENU_ITEM) #define IDO_CALENDAR_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), IDO_TYPE_CALENDAR_MENU_ITEM, IdoCalendarMenuItemPrivate)) static void ido_calendar_menu_item_class_init (IdoCalendarMenuItemClass *klass) { GObjectClass *gobject_class; GtkWidgetClass *widget_class; GtkMenuItemClass *menu_item_class; gobject_class = G_OBJECT_CLASS (klass); widget_class = GTK_WIDGET_CLASS (klass); menu_item_class = GTK_MENU_ITEM_CLASS (klass); gobject_class->finalize = ido_calendar_menu_item_finalize; widget_class->button_release_event = ido_calendar_menu_item_button_release; widget_class->button_press_event = ido_calendar_menu_item_button_press; menu_item_class->select = ido_calendar_menu_item_select; menu_item_class->deselect = ido_calendar_menu_item_deselect; menu_item_class->hide_on_activate = TRUE; g_type_class_add_private (gobject_class, sizeof (IdoCalendarMenuItemPrivate)); g_signal_new("month-changed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); g_signal_new("day-selected", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); g_signal_new("day-selected-double-click", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void ido_calendar_menu_item_init (IdoCalendarMenuItem *item) { IdoCalendarMenuItemPrivate *priv; priv = item->priv = IDO_CALENDAR_MENU_ITEM_GET_PRIVATE (item); /* Will be disposed automatically */ priv->calendar = g_object_new (gtk_calendar_get_type (), NULL); g_object_add_weak_pointer (G_OBJECT (priv->calendar), (gpointer*) &priv->calendar); g_signal_connect (priv->calendar, "realize", G_CALLBACK (calendar_realized_cb), item); g_signal_connect (priv->calendar, "move-focus", G_CALLBACK (calendar_move_focus_cb), item); priv->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start (GTK_BOX (priv->box), priv->calendar, FALSE, FALSE, 0); gtk_container_add (GTK_CONTAINER (item), priv->box); gtk_widget_show_all (priv->box); } static void ido_calendar_menu_item_finalize (GObject *object) { IdoCalendarMenuItem *item = IDO_CALENDAR_MENU_ITEM (object); IdoCalendarMenuItemPrivate *priv = IDO_CALENDAR_MENU_ITEM_GET_PRIVATE (item); if (G_IS_OBJECT (priv->calendar)) { g_object_remove_weak_pointer (G_OBJECT (priv->calendar), (gpointer*) &priv->calendar); g_signal_handlers_disconnect_by_data (priv->calendar, item); } if (G_IS_OBJECT (priv->parent)) { g_object_remove_weak_pointer (G_OBJECT (priv->parent), (gpointer*) &priv->parent); g_signal_handlers_disconnect_by_data (priv->parent, item); } G_OBJECT_CLASS (ido_calendar_menu_item_parent_class)->finalize (object); } static void ido_calendar_menu_item_send_focus_change (GtkWidget *widget, gboolean in) { GdkEvent *event = gdk_event_new (GDK_FOCUS_CHANGE); g_object_ref (widget); if (in) gtk_widget_grab_focus (widget); event->focus_change.type = GDK_FOCUS_CHANGE; event->focus_change.window = g_object_ref (gtk_widget_get_window (widget)); event->focus_change.in = in; gtk_widget_event (widget, event); g_object_notify (G_OBJECT (widget), "has-focus"); g_object_unref (widget); gdk_event_free (event); } static gboolean ido_calendar_menu_item_key_press (GtkWidget *widget, GdkEventKey *event, gpointer data) { IdoCalendarMenuItem *menuitem = (IdoCalendarMenuItem *)data; g_return_val_if_fail (IDO_IS_CALENDAR_MENU_ITEM (menuitem), FALSE); if (menuitem->priv->selected) { GtkWidget *calendar = menuitem->priv->calendar; gtk_widget_event (calendar, ((GdkEvent *)(void*)(event))); if (gtk_widget_get_window (calendar) != NULL) { gdk_window_raise (gtk_widget_get_window (calendar)); } if (!gtk_widget_has_focus (calendar)) { gtk_widget_grab_focus (calendar); } return (event->keyval != GDK_KEY_Return) && (event->keyval != GDK_KEY_Escape); } return FALSE; } static gboolean ido_calendar_menu_item_button_press (GtkWidget *widget, GdkEventButton *event) { GtkWidget *calendar = IDO_CALENDAR_MENU_ITEM (widget)->priv->calendar; if (event->button == 1) { if (gtk_widget_get_window (calendar) != NULL) { gdk_window_raise (gtk_widget_get_window (calendar)); } if (!gtk_widget_has_focus (calendar)) { gtk_widget_grab_focus (calendar); } GdkEvent * newevent = gdk_event_copy((GdkEvent *)(event)); GList * children = gdk_window_get_children(gtk_widget_get_window(calendar)); GList * child; gint root_x = event->x_root; gint root_y = event->y_root; for (child = children; child != NULL; child = g_list_next(child)) { gint newx, newy; gint winx, winy; GdkWindow * newwindow = (GdkWindow*)child->data; ((GdkEventButton *)newevent)->window = newwindow; gdk_window_get_origin(newwindow, &winx, &winy); newx = root_x - winx; newy = root_y - winy; if (newx >= 0 && newy >= 0 && newx < gdk_window_get_width(newwindow) && newy < gdk_window_get_height(newwindow)) { ((GdkEventButton *)newevent)->x = newx; ((GdkEventButton *)newevent)->y = newy; GTK_WIDGET_GET_CLASS(calendar)->button_press_event(GTK_WIDGET(calendar), (GdkEventButton*)newevent); } } ((GdkEventButton *)newevent)->window = event->window; gdk_event_free(newevent); return TRUE; } return FALSE; } static gboolean ido_calendar_menu_item_button_release (GtkWidget *widget, GdkEventButton *event) { GtkWidget *calendar = IDO_CALENDAR_MENU_ITEM (widget)->priv->calendar; GTK_WIDGET_GET_CLASS(calendar)->button_release_event(GTK_WIDGET(calendar), event); return TRUE; } static void ido_calendar_menu_item_select (GtkMenuItem *item) { IDO_CALENDAR_MENU_ITEM (item)->priv->selected = TRUE; ido_calendar_menu_item_send_focus_change (GTK_WIDGET (IDO_CALENDAR_MENU_ITEM (item)->priv->calendar), TRUE); } static void ido_calendar_menu_item_deselect (GtkMenuItem *item) { IDO_CALENDAR_MENU_ITEM (item)->priv->selected = FALSE; ido_calendar_menu_item_send_focus_change (GTK_WIDGET (IDO_CALENDAR_MENU_ITEM (item)->priv->calendar), FALSE); } static void calendar_realized_cb (GtkWidget *widget, IdoCalendarMenuItem *item) { if (gtk_widget_get_window (widget) != NULL) { gdk_window_raise (gtk_widget_get_window (widget)); } item->priv->parent = gtk_widget_get_parent (GTK_WIDGET (item)); g_object_add_weak_pointer (G_OBJECT (item->priv->parent), (gpointer*) &item->priv->parent); g_signal_connect (item->priv->parent, "key-press-event", G_CALLBACK (ido_calendar_menu_item_key_press), item); g_signal_connect (item->priv->calendar, "month-changed", G_CALLBACK (calendar_month_changed_cb), item); g_signal_connect (item->priv->calendar, "day-selected", G_CALLBACK (calendar_day_selected_cb), item); g_signal_connect (item->priv->calendar, "day-selected-double-click", G_CALLBACK (calendar_day_selected_double_click_cb), item); ido_calendar_menu_item_send_focus_change (widget, TRUE); } static void calendar_move_focus_cb (GtkWidget *widget, GtkDirectionType direction, IdoCalendarMenuItem *item) { ido_calendar_menu_item_send_focus_change (GTK_WIDGET (IDO_CALENDAR_MENU_ITEM (item)->priv->calendar), FALSE); g_signal_emit_by_name (item, "move-focus", GTK_DIR_TAB_FORWARD); } static void calendar_month_changed_cb (GtkWidget *widget, gpointer user_data) { IdoCalendarMenuItem *item = (IdoCalendarMenuItem *)user_data; g_signal_emit_by_name (item, "month-changed", NULL); } static void calendar_day_selected_cb (GtkWidget *widget, gpointer user_data) { IdoCalendarMenuItem *item = (IdoCalendarMenuItem *)user_data; g_signal_emit_by_name (item, "day-selected", NULL); } static void calendar_day_selected_double_click_cb (GtkWidget *widget, gpointer user_data) { IdoCalendarMenuItem *item = (IdoCalendarMenuItem *)user_data; guint day, month, year; gtk_calendar_get_date (GTK_CALENDAR (widget), &year, &month, &day); g_signal_emit_by_name (item, "day-selected-double-click", NULL); } /** * ido_calendar_menu_item_new: * * Creates a new #IdoCalendarMenuItem * * Return Value: a new #IdoCalendarMenuItem. **/ GtkWidget * ido_calendar_menu_item_new (void) { return g_object_new (IDO_TYPE_CALENDAR_MENU_ITEM, NULL); } /** * ido_calendar_menu_item_get_calendar: * @menuitem: A #IdoCalendarMenuItem * * Returns the calendar associated with this menu item. * * Return Value: (transfer none): The #GtkCalendar used in this item. */ GtkWidget * ido_calendar_menu_item_get_calendar (IdoCalendarMenuItem *menuitem) { g_return_val_if_fail (IDO_IS_CALENDAR_MENU_ITEM (menuitem), NULL); return menuitem->priv->calendar; } /** * ido_calendar_menu_item_mark_day: * @menuitem: A #IdoCalendarMenuItem * @day: the day number to unmark between 1 and 31. * * Places a visual marker on a particular day. * * Return Value: #TRUE */ gboolean ido_calendar_menu_item_mark_day (IdoCalendarMenuItem *menuitem, guint day) { g_return_val_if_fail(IDO_IS_CALENDAR_MENU_ITEM(menuitem), FALSE); gtk_calendar_mark_day(GTK_CALENDAR (menuitem->priv->calendar), day); return TRUE; } /** * ido_calendar_menu_item_unmark_day: * @menuitem: A #IdoCalendarMenuItem * @day: the day number to unmark between 1 and 31. * * Removes the visual marker from a particular day. * * Return Value: #TRUE */ gboolean ido_calendar_menu_item_unmark_day (IdoCalendarMenuItem *menuitem, guint day) { g_return_val_if_fail(IDO_IS_CALENDAR_MENU_ITEM(menuitem), FALSE); gtk_calendar_unmark_day(GTK_CALENDAR (menuitem->priv->calendar), day); return TRUE; } /** * ido_calendar_menu_item_clear_marks: * @menuitem: A #IdoCalendarMenuItem * * Remove all visual markers. */ void ido_calendar_menu_item_clear_marks (IdoCalendarMenuItem *menuitem) { g_return_if_fail(IDO_IS_CALENDAR_MENU_ITEM(menuitem)); gtk_calendar_clear_marks(GTK_CALENDAR (menuitem->priv->calendar)); } /** * ido_calendar_menu_item_set_display_options: * @menuitem: A #IdoCalendarMenuItem * @flags: the display options to set * * Set the display options for the calendar. */ void ido_calendar_menu_item_set_display_options (IdoCalendarMenuItem *menuitem, GtkCalendarDisplayOptions flags) { g_return_if_fail(IDO_IS_CALENDAR_MENU_ITEM(menuitem)); gtk_calendar_set_display_options (GTK_CALENDAR (menuitem->priv->calendar), flags); } /** * ido_calendar_menu_item_get_display_options: * @menuitem: A #IdoCalendarMenuItem * * Get the display options for the calendar. * * Return Value: the display options in use */ GtkCalendarDisplayOptions ido_calendar_menu_item_get_display_options (IdoCalendarMenuItem *menuitem) { g_return_val_if_fail(IDO_IS_CALENDAR_MENU_ITEM(menuitem), 0); return gtk_calendar_get_display_options (GTK_CALENDAR (menuitem->priv->calendar)); } /** * ido_calendar_menu_item_get_date: * @menuitem: A #IdoCalendarMenuItem * @year: (out) (allow-none): location to store the year as a decimal number (e.g. 2011), or #NULL. * @month: (out) (allow-none): location to store the month number (between 0 and 11), or #NULL. * @day: (out) (allow-none): location to store the day number (between 1 and 31), or #NULL. * * Gets the selected date. */ void ido_calendar_menu_item_get_date (IdoCalendarMenuItem *menuitem, guint *year, guint *month, guint *day) { g_return_if_fail(IDO_IS_CALENDAR_MENU_ITEM(menuitem)); gtk_calendar_get_date (GTK_CALENDAR (menuitem->priv->calendar), year, month, day); } /** * ido_calendar_menu_item_set_date: * @menuitem: A #IdoCalendarMenuItem * @year: the year to show (e.g. 2011). * @month: a month number (between 0 and 11). * @day: The day number (between 1 and 31). * * Set the date shown on the calendar. * * Return Value: #TRUE */ gboolean ido_calendar_menu_item_set_date (IdoCalendarMenuItem *menuitem, guint year, guint month, guint day) { guint old_y, old_m, old_d; g_return_val_if_fail (IDO_IS_CALENDAR_MENU_ITEM(menuitem), FALSE); ido_calendar_menu_item_get_date (menuitem, &old_y, &old_m, &old_d); if ((old_y != year) || (old_m != month)) gtk_calendar_select_month (GTK_CALENDAR (menuitem->priv->calendar), month, year); if (old_d != day) gtk_calendar_select_day (GTK_CALENDAR (menuitem->priv->calendar), day); return TRUE; } /*** **** **** **** ***/ static void activate_current_day (IdoCalendarMenuItem * ido_calendar, const char * action_name_key) { GObject * o; const char * action_name; GActionGroup * action_group; o = G_OBJECT (ido_calendar); action_name = g_object_get_data (o, action_name_key); action_group = g_object_get_data (o, "ido-action-group"); if (action_group && action_name) { guint y, m, d; GDateTime * date_time; GVariant * target; ido_calendar_menu_item_get_date (ido_calendar, &y, &m, &d); m++; /* adjust month from GtkCalendar (0 based) to GDateTime (1 based) */ date_time = g_date_time_new_local (y, m, d, 9, 0, 0); target = g_variant_new_int64 (g_date_time_to_unix (date_time)); g_action_group_activate_action (action_group, action_name, target); g_date_time_unref (date_time); } } static void on_day_selected (IdoCalendarMenuItem * ido_calendar) { activate_current_day (ido_calendar, "ido-selection-action-name"); } static void on_day_double_clicked (IdoCalendarMenuItem * ido_calendar) { activate_current_day (ido_calendar, "ido-activation-action-name"); } static void on_action_state_changed (IdoActionHelper * helper, GVariant * state, gpointer unused G_GNUC_UNUSED) { GVariant * v; const char * key; IdoCalendarMenuItem * ido_calendar; ido_calendar = IDO_CALENDAR_MENU_ITEM (ido_action_helper_get_widget (helper)); g_return_if_fail (ido_calendar != NULL); g_return_if_fail (g_variant_is_of_type (state, G_VARIANT_TYPE_DICTIONARY)); /* an int64 representing a time_t indicating which year and month should be visible in the calendar and which day should be given the cursor. */ key = "calendar-day"; if ((v = g_variant_lookup_value (state, key, G_VARIANT_TYPE_INT64))) { int y, m, d; time_t t; GDateTime * date_time; t = g_variant_get_int64 (v); date_time = g_date_time_new_from_unix_local (t); g_date_time_get_ymd (date_time, &y, &m, &d); m--; /* adjust month from GDateTime (1 based) to GtkCalendar (0 based) */ ido_calendar_menu_item_set_date (ido_calendar, y, m, d); g_date_time_unref (date_time); g_variant_unref (v); } /* a boolean value of whether or not to show the week numbers */ key = "show-week-numbers"; if ((v = g_variant_lookup_value (state, key, G_VARIANT_TYPE_BOOLEAN))) { const GtkCalendarDisplayOptions old_flags = ido_calendar_menu_item_get_display_options (ido_calendar); GtkCalendarDisplayOptions new_flags = old_flags; if (g_variant_get_boolean (v)) new_flags |= GTK_CALENDAR_SHOW_WEEK_NUMBERS; else new_flags &= ~GTK_CALENDAR_SHOW_WEEK_NUMBERS; if (new_flags != old_flags) ido_calendar_menu_item_set_display_options (ido_calendar, new_flags); g_variant_unref (v); } /* an array of int32 day-of-months denoting days that have appointments */ key = "appointment-days"; ido_calendar_menu_item_clear_marks (ido_calendar); if ((v = g_variant_lookup_value (state, key, G_VARIANT_TYPE("ai")))) { gint32 day; GVariantIter iter; g_variant_iter_init (&iter, v); while (g_variant_iter_next (&iter, "i", &day)) ido_calendar_menu_item_mark_day (ido_calendar, day); g_variant_unref (v); } } GtkMenuItem * ido_calendar_menu_item_new_from_model (GMenuItem * menu_item, GActionGroup * actions) { GObject * o; GtkWidget * calendar; IdoCalendarMenuItem * ido_calendar; gchar * selection_action_name = NULL; gchar * activation_action_name = NULL; /* get the select & activate action names */ g_menu_item_get_attribute (menu_item, "action", "s", &selection_action_name); g_menu_item_get_attribute (menu_item, "activation-action", "s", &activation_action_name); /* remember the action group & action names so that we can poke them when user selects and double-clicks */ ido_calendar = IDO_CALENDAR_MENU_ITEM (ido_calendar_menu_item_new ()); o = G_OBJECT (ido_calendar); g_object_set_data_full (o, "ido-action-group", g_object_ref(actions), g_object_unref); g_object_set_data_full (o, "ido-selection-action-name", selection_action_name, g_free); g_object_set_data_full (o, "ido-activation-action-name", activation_action_name, g_free); calendar = ido_calendar_menu_item_get_calendar (ido_calendar); g_signal_connect_swapped (calendar, "day-selected", G_CALLBACK(on_day_selected), ido_calendar); g_signal_connect_swapped (calendar, "day-selected-double-click", G_CALLBACK(on_day_double_clicked), ido_calendar); /* Use an IdoActionHelper for state updates. Since we have two separate actions for selection & activation, we'll do the activation & targets logic here in ido-calendar */ if (selection_action_name != NULL) { IdoActionHelper * helper; helper = ido_action_helper_new (GTK_WIDGET(ido_calendar), actions, selection_action_name, NULL); g_signal_connect (helper, "action-state-changed", G_CALLBACK (on_action_state_changed), NULL); g_signal_connect_swapped (ido_calendar, "destroy", G_CALLBACK (g_object_unref), helper); } return GTK_MENU_ITEM (ido_calendar); } ./src/idotimeline.h0000644000004100000410000001163714320114711014507 0ustar www-datawww-data/* * Copyright (C) 2007 Carlos Garnacho * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef __IDO_TIMELINE_H__ #define __IDO_TIMELINE_H__ #include #include #include G_BEGIN_DECLS #define IDO_TYPE_TIMELINE (ido_timeline_get_type ()) #define IDO_TIMELINE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), IDO_TYPE_TIMELINE, IdoTimeline)) #define IDO_TIMELINE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), IDO_TYPE_TIMELINE, IdoTimelineClass)) #define IDO_IS_TIMELINE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), IDO_TYPE_TIMELINE)) #define IDO_IS_TIMELINE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), IDO_TYPE_TIMELINE)) #define IDO_TIMELINE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), IDO_TYPE_TIMELINE, IdoTimelineClass)) typedef struct IdoTimeline IdoTimeline; typedef struct IdoTimelineClass IdoTimelineClass; typedef enum { IDO_TIMELINE_DIRECTION_FORWARD, IDO_TIMELINE_DIRECTION_BACKWARD } IdoTimelineDirection; typedef enum { IDO_TIMELINE_PROGRESS_LINEAR, IDO_TIMELINE_PROGRESS_SINUSOIDAL, IDO_TIMELINE_PROGRESS_EXPONENTIAL, IDO_TIMELINE_PROGRESS_EASE_IN_EASE_OUT } IdoTimelineProgressType; struct IdoTimeline { GObject parent_instance; }; struct IdoTimelineClass { GObjectClass parent_class; void (* started) (IdoTimeline *timeline); void (* finished) (IdoTimeline *timeline); void (* paused) (IdoTimeline *timeline); void (* frame) (IdoTimeline *timeline, gdouble progress); void (* __ido_reserved1) (void); void (* __ido_reserved2) (void); void (* __ido_reserved3) (void); void (* __ido_reserved4) (void); }; GType ido_timeline_get_type (void) G_GNUC_CONST; IdoTimeline *ido_timeline_new (guint duration); IdoTimeline *ido_timeline_new_for_screen (guint duration, GdkScreen *screen); void ido_timeline_start (IdoTimeline *timeline); void ido_timeline_pause (IdoTimeline *timeline); void ido_timeline_rewind (IdoTimeline *timeline); gboolean ido_timeline_is_running (IdoTimeline *timeline); guint ido_timeline_get_fps (IdoTimeline *timeline); void ido_timeline_set_fps (IdoTimeline *timeline, guint fps); gboolean ido_timeline_get_loop (IdoTimeline *timeline); void ido_timeline_set_loop (IdoTimeline *timeline, gboolean loop); guint ido_timeline_get_duration (IdoTimeline *timeline); void ido_timeline_set_duration (IdoTimeline *timeline, guint duration); GdkScreen *ido_timeline_get_screen (IdoTimeline *timeline); void ido_timeline_set_screen (IdoTimeline *timeline, GdkScreen *screen); IdoTimelineDirection ido_timeline_get_direction (IdoTimeline *timeline); void ido_timeline_set_direction (IdoTimeline *timeline, IdoTimelineDirection direction); gdouble ido_timeline_get_progress (IdoTimeline *timeline); void ido_timeline_set_progress (IdoTimeline *timeline, gdouble progress); gdouble ido_timeline_calculate_progress (gdouble linear_progress, IdoTimelineProgressType progress_type); G_END_DECLS #endif /* __IDO_TIMELINE_H__ */ ./src/idomessagedialog.c0000644000004100000410000003262614320114711015501 0ustar www-datawww-data/* * Copyright (C) 2010 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of either or both of the following licenses: * * 1) the GNU Lesser General Public License version 3, as published by the * Free Software Foundation; and/or * 2) the GNU Lesser General Public License version 2.1, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License version 3 and version 2.1 along with this program. If not, see * * * Authors: * Cody Russell * * Design and specification: * Matthew Paul Thomas */ #include #include #include "idomessagedialog.h" #include "idotimeline.h" #include "config.h" #define IDO_MESSAGE_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), IDO_TYPE_MESSAGE_DIALOG, IdoMessageDialogPrivate)) static GtkWidget *ido_message_dialog_get_secondary_label (IdoMessageDialog *dialog); static GtkWidget *ido_message_dialog_get_primary_label (IdoMessageDialog *dialog); typedef struct _IdoMessageDialogPrivate IdoMessageDialogPrivate; typedef struct _IdoMessageDialogMorphContext IdoMessageDialogMorphContext; struct _IdoMessageDialogPrivate { GtkWidget *action_area; GtkWidget *primary_label; GtkWidget *secondary_label; gboolean expanded; }; struct _IdoMessageDialogMorphContext { GtkWidget *widget; IdoTimeline *timeline; GtkRequisition start; GtkRequisition end; }; G_DEFINE_TYPE (IdoMessageDialog, ido_message_dialog, GTK_TYPE_MESSAGE_DIALOG) static void ido_message_dialog_map (GtkWidget *widget) { IdoMessageDialog *dialog = IDO_MESSAGE_DIALOG (widget); IdoMessageDialogPrivate *priv = IDO_MESSAGE_DIALOG_GET_PRIVATE (dialog); GTK_WIDGET_CLASS (ido_message_dialog_parent_class)->map (widget); priv->primary_label = ido_message_dialog_get_primary_label (dialog); priv->secondary_label = ido_message_dialog_get_secondary_label (dialog); gtk_widget_hide (priv->secondary_label); gtk_label_set_selectable (GTK_LABEL (priv->primary_label), FALSE); gtk_label_set_selectable (GTK_LABEL (priv->secondary_label), FALSE); /* XXX: We really want to use gtk_window_set_deletable (GTK_WINDOW (widget), FALSE) * here, but due to a bug in compiz this is more compatible. * * See: https://bugs.launchpad.net/ubuntu/+source/compiz/+bug/240794 */ gdk_window_set_functions (gtk_widget_get_window (widget), GDK_FUNC_RESIZE | GDK_FUNC_MOVE); ido_message_dialog_get_secondary_label (IDO_MESSAGE_DIALOG (widget)); } static IdoMessageDialogMorphContext * ido_message_dialog_morph_context_new (GtkWidget *widget, IdoTimeline *timeline, gpointer identifier, GtkRequisition *start, GtkRequisition *end) { IdoMessageDialogMorphContext *context; context = g_slice_new (IdoMessageDialogMorphContext); context->widget = widget; context->timeline = timeline; context->start = *start; context->end = *end; return context; } static void ido_message_dialog_morph_context_free (IdoMessageDialogMorphContext *context) { g_object_unref (context->timeline); g_slice_free (IdoMessageDialogMorphContext, context); } static void timeline_frame_cb (IdoTimeline *timeline, gdouble progress, gpointer user_data) { IdoMessageDialogMorphContext *context = user_data; GtkRequisition start = context->start; GtkRequisition end = context->end; gint width_diff; gint height_diff; gint width, height; width_diff = (MAX(start.width, end.width) - MIN(start.width, end.width)) * progress; height_diff = (MAX(start.height, end.height) - MIN(start.height, end.height)) * progress; gtk_window_get_size (GTK_WINDOW (context->widget), &width, &height); gtk_widget_set_size_request (context->widget, width_diff ? start.width + width_diff : -1, height_diff ? start.height + height_diff : -1); } static void timeline_finished_cb (IdoTimeline *timeline, gpointer user_data) { IdoMessageDialogMorphContext *context = user_data; IdoMessageDialogPrivate *priv = IDO_MESSAGE_DIALOG_GET_PRIVATE (context->widget); gtk_widget_show (priv->action_area); gtk_widget_show (priv->secondary_label); ido_message_dialog_morph_context_free (context); } static gboolean ido_message_dialog_focus_in_event (GtkWidget *widget, GdkEventFocus *event) { IdoMessageDialog *dialog = IDO_MESSAGE_DIALOG (widget); IdoMessageDialogPrivate *priv = IDO_MESSAGE_DIALOG_GET_PRIVATE (dialog); if (!priv->expanded) { GtkRequisition start; GtkRequisition end; IdoTimeline *timeline; IdoMessageDialogMorphContext *context; gtk_widget_get_preferred_size (GTK_WIDGET (dialog), NULL, &start); priv->expanded = TRUE; gtk_widget_show (priv->action_area); gtk_widget_show (priv->secondary_label); gtk_widget_get_preferred_size (GTK_WIDGET (dialog), NULL, &end); gtk_widget_hide (priv->action_area); gtk_widget_hide (priv->secondary_label); timeline = ido_timeline_new (500); context = ido_message_dialog_morph_context_new (GTK_WIDGET (dialog), timeline, "foo", &start, &end); g_signal_connect (timeline, "frame", G_CALLBACK (timeline_frame_cb), context); g_signal_connect (timeline, "finished", G_CALLBACK (timeline_finished_cb), context); ido_timeline_start (timeline); } return FALSE; } static void ido_message_dialog_constructed (GObject *object) { IdoMessageDialogPrivate *priv = IDO_MESSAGE_DIALOG_GET_PRIVATE (object); GtkWidget *vbox; GtkWidget *event_box; event_box = gtk_event_box_new (); gtk_widget_show (event_box); vbox = gtk_dialog_get_content_area (GTK_DIALOG (object)); priv->action_area = gtk_dialog_get_action_area (GTK_DIALOG (object)); g_object_ref (G_OBJECT (vbox)); gtk_container_remove (GTK_CONTAINER (object), vbox); gtk_container_add (GTK_CONTAINER (event_box), vbox); gtk_container_add (GTK_CONTAINER (object), event_box); gtk_widget_hide (priv->action_area); } static void ido_message_dialog_class_init (IdoMessageDialogClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); object_class->constructed = ido_message_dialog_constructed; widget_class->map = ido_message_dialog_map; widget_class->focus_in_event = ido_message_dialog_focus_in_event; g_type_class_add_private (object_class, sizeof (IdoMessageDialogPrivate)); } static void ido_message_dialog_init (IdoMessageDialog *dialog) { gtk_window_set_focus_on_map (GTK_WINDOW (dialog), FALSE); } /** * ido_message_dialog_new: * @parent: transient parent, or %NULL for none * @flags: flags * @type: type of message * @buttons: a set of buttons to use * @message_format: printf()-style format string, or %NULL * @...: arguments for @message_format * * Creates a new message dialog, which is based upon * GtkMessageDialog so it shares API and functionality * with it. IdoMessageDialog differs in that it has two * states. The initial state hides the action buttons * and the secondary message. When a user clicks on the * dialog it will expand to provide the secondary message * and the action buttons. * * Return Value: a new #IdoMessageDialog **/ GtkWidget* ido_message_dialog_new (GtkWindow *parent, GtkDialogFlags flags, GtkMessageType type, GtkButtonsType buttons, const gchar *message_format, ...) { GtkWidget *widget; GtkDialog *dialog; gchar* msg = NULL; va_list args; g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), NULL); widget = g_object_new (IDO_TYPE_MESSAGE_DIALOG, "message-type", type, "buttons", buttons, NULL); dialog = GTK_DIALOG (widget); if (message_format) { va_start (args, message_format); msg = g_strdup_vprintf (message_format, args); va_end (args); g_object_set (G_OBJECT (widget), "text", msg, NULL); g_free (msg); } if (parent != NULL) gtk_window_set_transient_for (GTK_WINDOW (widget), GTK_WINDOW (parent)); if (flags & GTK_DIALOG_MODAL) gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); if (flags & GTK_DIALOG_DESTROY_WITH_PARENT) gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE); return widget; } /** * ido_message_dialog_new_with_markup: * @parent: transient parent, or %NULL for none * @flags: flags * @type: type of message * @buttons: a set of buttons to use * @message_format: printf()-style format string, or %NULL * @...: arguments for @message_format. They will be escaped to allow valid XML. * * Creates a new message dialog, which is based upon * GtkMessageDialog so it shares API and functionality * with it. IdoMessageDialog differs in that it has two * states. The initial state hides the action buttons * and the secondary message. When a user clicks on the * dialog it will expand to provide the secondary message * and the action buttons. * * Return Value: a new #IdoMessageDialog **/ GtkWidget* ido_message_dialog_new_with_markup (GtkWindow *parent, GtkDialogFlags flags, GtkMessageType type, GtkButtonsType buttons, const gchar *message_format, ...) { GtkWidget *widget; va_list args; gchar *msg = NULL; g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), NULL); widget = ido_message_dialog_new (parent, flags, type, buttons, NULL); if (message_format) { va_start (args, message_format); msg = g_markup_vprintf_escaped (message_format, args); va_end (args); gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (widget), msg); g_free (msg); } return widget; } /* * This is almost humorously stupid. We jump through some hoops and kill * a few kittens here because we want to preserve API compatibility with * GtkMessageDialog and extend it instead of duplicating its functionality. * If only GtkMessageDialog were easier to extend then maybe all those * kittens wouldn't have had to die... */ static GtkWidget * ido_message_dialog_get_label (IdoMessageDialog *dialog, gboolean primary) { GList *list; gchar *text; gchar *secondary_text; GtkWidget *content; GList *children; g_object_get (G_OBJECT (dialog), "text", &text, "secondary-text", &secondary_text, NULL); g_return_val_if_fail (IDO_IS_MESSAGE_DIALOG (dialog), NULL); content = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); children = gtk_container_get_children (GTK_CONTAINER (content)); for (list = children; list != NULL; list = list->next) { if (G_TYPE_FROM_INSTANCE (list->data) == GTK_TYPE_BOX && gtk_orientable_get_orientation (list->data) == GTK_ORIENTATION_HORIZONTAL) { GList *hchildren; GList *hlist; GtkWidget *hbox = GTK_WIDGET (list->data); hchildren = gtk_container_get_children (GTK_CONTAINER (hbox)); for (hlist = hchildren; hlist != NULL; hlist = hlist->next) { if (G_TYPE_FROM_INSTANCE (hlist->data) == GTK_TYPE_BOX && gtk_orientable_get_orientation (hlist->data) == GTK_ORIENTATION_VERTICAL) { GList *vlist; GtkWidget *vbox = GTK_WIDGET (hlist->data); GList *vchildren; vchildren = gtk_container_get_children (GTK_CONTAINER (vbox)); for (vlist = vchildren; vlist != NULL; vlist = vlist->next) { GtkLabel *label; label = GTK_LABEL (vlist->data); if (strcmp ((primary ? text : secondary_text), gtk_label_get_label (label)) == 0) { return GTK_WIDGET (label); } } } } } } return NULL; } static GtkWidget * ido_message_dialog_get_secondary_label (IdoMessageDialog *dialog) { return ido_message_dialog_get_label (dialog, FALSE); } static GtkWidget * ido_message_dialog_get_primary_label (IdoMessageDialog *dialog) { return ido_message_dialog_get_label (dialog, TRUE); } ./src/idobasicmenuitem.c0000644000004100000410000002500514320114711015513 0ustar www-datawww-data/* * Copyright 2013 Canonical Ltd. * * Authors: * Charles Kerr * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "idoactionhelper.h" #include "idobasicmenuitem.h" enum { PROP_0, PROP_ICON, PROP_TEXT, PROP_SECONDARY_TEXT, PROP_LAST }; static GParamSpec *properties[PROP_LAST]; struct _IdoBasicMenuItemPrivate { GIcon * icon; char * text; char * secondary_text; GtkWidget * image; GtkWidget * label; GtkWidget * secondary_label; }; typedef IdoBasicMenuItemPrivate priv_t; G_DEFINE_TYPE (IdoBasicMenuItem, ido_basic_menu_item, GTK_TYPE_MENU_ITEM); /*** **** GObject Virtual Functions ***/ static void my_get_property (GObject * o, guint property_id, GValue * value, GParamSpec * pspec) { IdoBasicMenuItem * self = IDO_BASIC_MENU_ITEM (o); priv_t * p = self->priv; switch (property_id) { case PROP_ICON: g_value_set_object (value, p->icon); break; case PROP_TEXT: g_value_set_string (value, p->text); break; case PROP_SECONDARY_TEXT: g_value_set_string (value, p->secondary_text); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); break; } } static void my_set_property (GObject * o, guint property_id, const GValue * value, GParamSpec * pspec) { IdoBasicMenuItem * self = IDO_BASIC_MENU_ITEM (o); switch (property_id) { case PROP_ICON: ido_basic_menu_item_set_icon (self, g_value_get_object (value)); break; case PROP_TEXT: ido_basic_menu_item_set_text (self, g_value_get_string (value)); break; case PROP_SECONDARY_TEXT: ido_basic_menu_item_set_secondary_text (self, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); break; } } static void my_dispose (GObject * object) { IdoBasicMenuItem * self = IDO_BASIC_MENU_ITEM (object); priv_t * p = self->priv; g_clear_object (&p->icon); G_OBJECT_CLASS (ido_basic_menu_item_parent_class)->dispose (object); } static void my_finalize (GObject * object) { IdoBasicMenuItem * self = IDO_BASIC_MENU_ITEM (object); priv_t * p = self->priv; g_free (p->text); g_free (p->secondary_text); G_OBJECT_CLASS (ido_basic_menu_item_parent_class)->finalize (object); } static void ido_basic_menu_item_update_image (IdoBasicMenuItem *self) { IdoBasicMenuItemPrivate * p = self->priv; gtk_image_clear (GTK_IMAGE (p->image)); if (p->icon == NULL) { gtk_widget_set_visible (p->image, FALSE); } else { GtkIconInfo *info; const gchar *filename; info = gtk_icon_theme_lookup_by_gicon (gtk_icon_theme_get_default (), p->icon, 16, 0); filename = gtk_icon_info_get_filename (info); if (filename) { GdkPixbuf *pixbuf; pixbuf = gdk_pixbuf_new_from_file_at_scale (filename, -1, 16, TRUE, NULL); gtk_image_set_from_pixbuf (GTK_IMAGE (p->image), pixbuf); g_object_unref (pixbuf); } gtk_widget_set_visible (p->image, filename != NULL); g_object_unref (info); } } static void ido_basic_menu_item_style_updated (GtkWidget *widget) { GTK_WIDGET_CLASS (ido_basic_menu_item_parent_class)->style_updated (widget); ido_basic_menu_item_update_image (IDO_BASIC_MENU_ITEM (widget)); gtk_widget_queue_draw (widget); } /*** **** Instantiation ***/ static void ido_basic_menu_item_class_init (IdoBasicMenuItemClass *klass) { GParamFlags prop_flags; GObjectClass * gobject_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); g_type_class_add_private (klass, sizeof (IdoBasicMenuItemPrivate)); gobject_class->get_property = my_get_property; gobject_class->set_property = my_set_property; gobject_class->dispose = my_dispose; gobject_class->finalize = my_finalize; widget_class->style_updated = ido_basic_menu_item_style_updated; prop_flags = G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS; properties[PROP_ICON] = g_param_spec_object ("icon", "Icon", "The menuitem's GIcon", G_TYPE_OBJECT, prop_flags); properties[PROP_TEXT] = g_param_spec_string ("text", "Text", "The menuitem's text", "", prop_flags); properties[PROP_SECONDARY_TEXT] = g_param_spec_string ("secondary-text", "Secondary Text", "The menuitem's secondary text", "", prop_flags); g_object_class_install_properties (gobject_class, PROP_LAST, properties); } static void ido_basic_menu_item_init (IdoBasicMenuItem *self) { priv_t * p; GtkWidget * w; GtkGrid * grid; self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, IDO_TYPE_BASIC_MENU_ITEM, IdoBasicMenuItemPrivate); p = self->priv; p->image = gtk_image_new (); gtk_misc_set_alignment(GTK_MISC(p->image), 0.0, 0.0); p->label = gtk_label_new (""); gtk_misc_set_alignment (GTK_MISC(p->label), 0.0, 0.5); p->secondary_label = gtk_label_new (""); gtk_misc_set_alignment (GTK_MISC(p->secondary_label), 1.0, 0.5); w = gtk_grid_new (); grid = GTK_GRID (w); gtk_grid_attach (grid, p->image, 0, 0, 1, 1); gtk_grid_attach (grid, p->label, 1, 0, 1, 1); gtk_grid_attach (grid, p->secondary_label, 2, 0, 1, 1); g_object_set (p->image, "halign", GTK_ALIGN_START, "hexpand", FALSE, "valign", GTK_ALIGN_CENTER, "margin-right", 6, NULL); g_object_set (p->label, "halign", GTK_ALIGN_START, "hexpand", TRUE, "margin-right", 6, "valign", GTK_ALIGN_CENTER, NULL); g_object_set (p->secondary_label, "halign", GTK_ALIGN_END, "hexpand", FALSE, "valign", GTK_ALIGN_CENTER, NULL); gtk_widget_show (w); gtk_container_add (GTK_CONTAINER (self), w); } /*** **** Public API ***/ /* create a new IdoBasicMenuItem */ GtkWidget * ido_basic_menu_item_new (void) { return GTK_WIDGET (g_object_new (IDO_TYPE_BASIC_MENU_ITEM, NULL)); } void ido_basic_menu_item_set_icon (IdoBasicMenuItem * self, GIcon * icon) { IdoBasicMenuItemPrivate * p = self->priv; if (p->icon != icon) { if (p->icon) g_object_unref (p->icon); p->icon = icon ? g_object_ref (icon) : NULL; ido_basic_menu_item_update_image (self); } } void ido_basic_menu_item_set_icon_from_file (IdoBasicMenuItem * self, const char * filename) { GFile * file = filename ? g_file_new_for_path (filename) : NULL; GIcon * icon = file ? g_file_icon_new (file) : NULL; ido_basic_menu_item_set_icon (self, icon); g_clear_object (&icon); g_clear_object (&file); } void ido_basic_menu_item_set_text (IdoBasicMenuItem * self, const char * text) { IdoBasicMenuItemPrivate * p = self->priv; if (g_strcmp0 (p->text, text)) { g_free (p->text); p->text = g_strdup (text); g_object_set (G_OBJECT(p->label), "label", p->text, "visible", (gboolean)(p->text && *p->text), NULL); } } void ido_basic_menu_item_set_secondary_text (IdoBasicMenuItem * self, const char * secondary_text) { IdoBasicMenuItemPrivate * p = self->priv; if (g_strcmp0 (p->secondary_text, secondary_text)) { g_free (p->secondary_text); p->secondary_text = g_strdup (secondary_text); g_object_set (G_OBJECT(p->secondary_label), "label", p->secondary_text, "visible", (gboolean)(p->secondary_text && *p->secondary_text), NULL); } } static void ido_basic_menu_item_activate (GtkMenuItem *item, gpointer user_data) { IdoActionHelper *helper = user_data; ido_action_helper_activate (helper); } GtkMenuItem * ido_basic_menu_item_new_from_model (GMenuItem * menu_item, GActionGroup * actions) { GtkWidget *item; gchar *label; gchar *action; GVariant *serialized_icon; item = ido_basic_menu_item_new (); if (g_menu_item_get_attribute (menu_item, "label", "s", &label)) { ido_basic_menu_item_set_text (IDO_BASIC_MENU_ITEM (item), label); g_free (label); } serialized_icon = g_menu_item_get_attribute_value (menu_item, "icon", NULL); if (serialized_icon) { GIcon *icon; icon = g_icon_deserialize (serialized_icon); ido_basic_menu_item_set_icon (IDO_BASIC_MENU_ITEM (item), icon); g_object_unref (icon); g_variant_unref (serialized_icon); } if (g_menu_item_get_attribute (menu_item, "action", "s", &action)) { IdoActionHelper *helper; GVariant *target; target = g_menu_item_get_attribute_value (menu_item, "target", NULL); helper = ido_action_helper_new (item, actions, action, target); g_signal_connect_object (item, "activate", G_CALLBACK (ido_basic_menu_item_activate), helper, 0); g_signal_connect_swapped (item, "destroy", G_CALLBACK (g_object_unref), helper); if (target) g_variant_unref (target); g_free (action); } return GTK_MENU_ITEM (item); } ./src/idorange.h0000644000004100000410000000433514320114711013772 0ustar www-datawww-data/* * Copyright (C) 2010 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of either or both of the following licenses: * * 1) the GNU Lesser General Public License version 3, as published by the * Free Software Foundation; and/or * 2) the GNU Lesser General Public License version 2.1, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License version 3 and version 2.1 along with this program. If not, see * * * Authors: * Cody Russell */ #ifndef __IDO_RANGE_H__ #define __IDO_RANGE_H__ #include G_BEGIN_DECLS #define IDO_TYPE_RANGE (ido_range_get_type ()) #define IDO_RANGE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), IDO_TYPE_RANGE, IdoRange)) #define IDO_RANGE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), IDO_TYPE_RANGE, IdoRangeClass)) #define IDO_IS_RANGE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), IDO_TYPE_RANGE)) #define IDO_IS_RANGE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), IDO_TYPE_RANGE)) #define IDO_RANGE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), IDO_TYPE_RANGE, IdoRangeClass)) typedef enum { IDO_RANGE_STYLE_DEFAULT, IDO_RANGE_STYLE_SMALL } IdoRangeStyle; typedef struct _IdoRange IdoRange; typedef struct _IdoRangePrivate IdoRangePrivate; typedef struct _IdoRangeClass IdoRangeClass; struct _IdoRange { GtkScale parent_instance; IdoRangePrivate *priv; }; struct _IdoRangeClass { GtkScaleClass parent_class; /* Padding for future expansion */ void (*_ido_reserved1) (void); void (*_ido_reserved2) (void); void (*_ido_reserved3) (void); void (*_ido_reserved4) (void); }; GType ido_range_get_type (void) G_GNUC_CONST; GtkWidget* ido_range_new (GObject *adj, IdoRangeStyle style); G_END_DECLS #endif /* __IDO_RANGE_H__ */ ./src/idoplaybackmenuitem.c0000644000004100000410000013753414320114711016233 0ustar www-datawww-data/* * Copyright 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * * Authors: * Conor Curran * Mirco Müller * Andrea Cimitan * Lars Uebernickel */ #include "config.h" #include "idoplaybackmenuitem.h" #include #include #define RECT_WIDTH 130.0f #define Y 7.0f #define INNER_RADIUS 12.5 #define MIDDLE_RADIUS 13.0f #define OUTER_RADIUS 14.5f #define CIRCLE_RADIUS 21.0f #define PREV_WIDTH 25.0f #define PREV_HEIGHT 17.0f #define NEXT_WIDTH 25.0f //PREV_WIDTH #define NEXT_HEIGHT 17.0f //PREV_HEIGHT #define TRI_WIDTH 11.0f #define TRI_HEIGHT 13.0f #define TRI_OFFSET 6.0f #define PREV_X -2.0f #define PREV_Y 13.0f #define NEXT_X 76.0f //prev_y #define NEXT_Y 13.0f //prev_y #define PAUSE_WIDTH 21.0f #define PAUSE_HEIGHT 27.0f #define BAR_WIDTH 4.5f #define BAR_HEIGHT 24.0f #define BAR_OFFSET 10.0f #define PAUSE_X 41.0f #define PAUSE_Y 7.0f #define PLAY_WIDTH 28.0f #define PLAY_HEIGHT 29.0f #define PLAY_PADDING 5.0f #define INNER_START_SHADE 0.98 #define INNER_END_SHADE 0.98 #define MIDDLE_START_SHADE 1.0 #define MIDDLE_END_SHADE 1.0 #define OUTER_START_SHADE 0.75 #define OUTER_END_SHADE 1.3 #define SHADOW_BUTTON_SHADE 0.8 #define OUTER_PLAY_START_SHADE 0.7 #define OUTER_PLAY_END_SHADE 1.38 #define BUTTON_START_SHADE 1.1 #define BUTTON_END_SHADE 0.9 #define BUTTON_SHADOW_SHADE 0.8 #define INNER_COMPRESSED_START_SHADE 1.0 #define INNER_COMPRESSED_END_SHADE 1.0 typedef enum { STATE_PAUSED, STATE_PLAYING, STATE_LAUNCHING } State; typedef enum { BUTTON_NONE, BUTTON_PREVIOUS, BUTTON_PLAYPAUSE, BUTTON_NEXT, N_BUTTONS } Button; typedef GtkMenuItemClass IdoPlaybackMenuItemClass; struct _IdoPlaybackMenuItem { GtkMenuItem parent; State current_state; Button cur_pushed_button; Button cur_hover_button; gboolean has_focus; gboolean keyboard_activated; /* TRUE if the current button was activated with a key */ GActionGroup *action_group; gchar *button_actions[N_BUTTONS]; }; G_DEFINE_TYPE (IdoPlaybackMenuItem, ido_playback_menu_item, GTK_TYPE_MENU_ITEM); static gboolean ido_playback_menu_item_draw (GtkWidget* button, cairo_t *cr); static void ido_playback_menu_item_dispose (GObject *object) { IdoPlaybackMenuItem *item = IDO_PLAYBACK_MENU_ITEM (object); if (item->action_group) { g_signal_handlers_disconnect_by_data (item->action_group, item); g_clear_object (&item->action_group); } G_OBJECT_CLASS (ido_playback_menu_item_parent_class)->dispose (object); } static void ido_playback_menu_item_finalize (GObject *object) { IdoPlaybackMenuItem *item = IDO_PLAYBACK_MENU_ITEM (object); gint i; for (i = 0; i < N_BUTTONS; i++) g_free (item->button_actions[i]); G_OBJECT_CLASS (ido_playback_menu_item_parent_class)->finalize (object); } static Button ido_playback_menu_item_get_button_at_pos (GtkWidget *item, gint x, gint y) { GtkAllocation alloc; gint left; /* 0 44 86 130 * 5 +------+ * 12 +-----+ +-----+ * |prev play next| * 40 +-----+ +-----+ * 47 +------+ */ gtk_widget_get_allocation (item, &alloc); left = alloc.x + (alloc.width - RECT_WIDTH) / 2; if (x > left && x < left + 44 && y > 12 && y < 40) return BUTTON_PREVIOUS; if (x > left + 44 && x < left + 86 && y > 5 && y < 47) return BUTTON_PLAYPAUSE; if (x > left + 86 && x < left + 130 && y > 12 && y < 40) return BUTTON_NEXT; return BUTTON_NONE; } static gboolean ido_playback_menu_item_parent_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data) { IdoPlaybackMenuItem *self = user_data; /* only listen to events when the playback menu item is selected */ if (!self->has_focus) return FALSE; switch (event->keyval) { case GDK_KEY_Left: self->cur_pushed_button = BUTTON_PREVIOUS; break; case GDK_KEY_Right: self->cur_pushed_button = BUTTON_NEXT; break; case GDK_KEY_space: if (self->cur_hover_button != BUTTON_NONE) self->cur_pushed_button = self->cur_hover_button; else self->cur_pushed_button = BUTTON_PLAYPAUSE; break; default: self->cur_pushed_button = BUTTON_NONE; } if (self->cur_pushed_button != BUTTON_NONE) { const gchar *action = self->button_actions[self->cur_pushed_button]; if (self->action_group && action) g_action_group_activate_action (self->action_group, action, NULL); self->keyboard_activated = TRUE; gtk_widget_queue_draw (widget); return TRUE; } return FALSE; } static gboolean ido_playback_menu_item_parent_key_release_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data) { IdoPlaybackMenuItem *self = user_data; switch (event->keyval) { case GDK_KEY_Left: case GDK_KEY_Right: case GDK_KEY_space: self->cur_pushed_button = BUTTON_NONE; self->keyboard_activated = FALSE; gtk_widget_queue_draw (widget); break; } return FALSE; } static void ido_playback_menu_item_parent_set (GtkWidget *widget, GtkWidget *old_parent) { GtkWidget *parent; /* Menus don't pass key events to their children. This works around * that by listening to key events on the parent widget. */ if (old_parent) { g_signal_handlers_disconnect_by_func (old_parent, ido_playback_menu_item_parent_key_press_event, widget); g_signal_handlers_disconnect_by_func (old_parent, ido_playback_menu_item_parent_key_release_event, widget); } parent = gtk_widget_get_parent (widget); if (parent) { g_signal_connect (parent, "key-press-event", G_CALLBACK (ido_playback_menu_item_parent_key_press_event), widget); g_signal_connect (parent, "key-release-event", G_CALLBACK (ido_playback_menu_item_parent_key_release_event), widget); } } static void ido_playback_menu_item_select (GtkMenuItem *item) { IdoPlaybackMenuItem *self = IDO_PLAYBACK_MENU_ITEM (item); self->has_focus = TRUE; GTK_MENU_ITEM_CLASS (ido_playback_menu_item_parent_class)->select (item); } static void ido_playback_menu_item_deselect (GtkMenuItem *item) { IdoPlaybackMenuItem *self = IDO_PLAYBACK_MENU_ITEM (item); self->has_focus = FALSE; GTK_MENU_ITEM_CLASS (ido_playback_menu_item_parent_class)->deselect (item); } static gboolean ido_playback_menu_item_button_press_event (GtkWidget *menuitem, GdkEventButton *event) { IdoPlaybackMenuItem *item = IDO_PLAYBACK_MENU_ITEM (menuitem); item->cur_pushed_button = ido_playback_menu_item_get_button_at_pos (menuitem, event->x, event->y); gtk_widget_queue_draw (menuitem); return TRUE; } static gboolean ido_playback_menu_item_button_release_event (GtkWidget *menuitem, GdkEventButton *event) { IdoPlaybackMenuItem *item = IDO_PLAYBACK_MENU_ITEM (menuitem); Button button; const gchar *action = action; button = ido_playback_menu_item_get_button_at_pos (menuitem, event->x, event->y); if (button != item->cur_pushed_button) button = BUTTON_NONE; action = item->button_actions[item->cur_pushed_button]; if (item->action_group && action) g_action_group_activate_action (item->action_group, action, NULL); item->cur_pushed_button = BUTTON_NONE; gtk_widget_queue_draw (menuitem); return TRUE; } static gboolean ido_playback_menu_item_motion_notify_event (GtkWidget *menuitem, GdkEventMotion *event) { IdoPlaybackMenuItem *item = IDO_PLAYBACK_MENU_ITEM (menuitem); item->cur_hover_button = ido_playback_menu_item_get_button_at_pos (menuitem, event->x, event->y); gtk_widget_queue_draw (menuitem); return TRUE; } static gboolean ido_playback_menu_item_leave_notify_event (GtkWidget *menuitem, GdkEventCrossing *event) { IdoPlaybackMenuItem *item = IDO_PLAYBACK_MENU_ITEM (menuitem); item->cur_pushed_button = BUTTON_NONE; item->cur_hover_button = BUTTON_NONE; gtk_widget_queue_draw (GTK_WIDGET(menuitem)); return TRUE; } static void ido_playback_menu_item_class_init (IdoPlaybackMenuItemClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); GtkMenuItemClass *menuitem_class = GTK_MENU_ITEM_CLASS (klass); gobject_class->dispose = ido_playback_menu_item_dispose; gobject_class->finalize = ido_playback_menu_item_finalize; widget_class->button_press_event = ido_playback_menu_item_button_press_event; widget_class->button_release_event = ido_playback_menu_item_button_release_event; widget_class->motion_notify_event = ido_playback_menu_item_motion_notify_event; widget_class->leave_notify_event = ido_playback_menu_item_leave_notify_event; widget_class->parent_set = ido_playback_menu_item_parent_set; widget_class->draw = ido_playback_menu_item_draw; menuitem_class->select = ido_playback_menu_item_select; menuitem_class->deselect = ido_playback_menu_item_deselect; } static void ido_playback_menu_item_init (IdoPlaybackMenuItem *self) { gtk_widget_set_size_request (GTK_WIDGET (self), 200, 43); } static void ido_playback_menu_item_set_state (IdoPlaybackMenuItem *self, State state) { self->current_state = state; if (self->current_state == STATE_LAUNCHING) gtk_widget_set_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_ACTIVE, FALSE); else gtk_widget_unset_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_ACTIVE); gtk_widget_queue_draw (GTK_WIDGET (self)); } static void ido_playback_menu_item_set_state_from_string (IdoPlaybackMenuItem *self, const gchar *state) { g_return_if_fail (state != NULL); if (g_str_equal (state, "Playing")) ido_playback_menu_item_set_state (self, STATE_PLAYING); else if (g_str_equal (state, "Launching")) ido_playback_menu_item_set_state (self, STATE_LAUNCHING); else /* "Paused" and fallback */ ido_playback_menu_item_set_state (self, STATE_PAUSED); } static void ido_playback_menu_item_action_added (GActionGroup *action_group, const gchar *action_name, gpointer user_data) { IdoPlaybackMenuItem *self = user_data; const gchar *action; action = self->button_actions[BUTTON_PLAYPAUSE]; if (action && g_str_equal (action_name, action)) { GVariant *state; state = g_action_group_get_action_state (action_group, action); if (g_variant_is_of_type (state, G_VARIANT_TYPE_STRING)) ido_playback_menu_item_set_state_from_string (self, g_variant_get_string (state, NULL)); g_variant_unref (state); } } static void ido_playback_menu_item_action_removed (GActionGroup *action_group, const gchar *action_name, gpointer user_data) { IdoPlaybackMenuItem *self = user_data; const gchar *action; action = self->button_actions[BUTTON_PLAYPAUSE]; if (action && g_str_equal (action_name, action)) ido_playback_menu_item_set_state (self, STATE_PAUSED); } static void ido_playback_menu_item_action_state_changed (GActionGroup *action_group, const gchar *action_name, GVariant *value, gpointer user_data) { IdoPlaybackMenuItem *self = user_data; const gchar *action; g_return_if_fail (action_name != NULL); action = self->button_actions[BUTTON_PLAYPAUSE]; if (action && g_str_equal (action_name, action)) { if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)) ido_playback_menu_item_set_state_from_string (self, g_variant_get_string (value, NULL)); } } GtkMenuItem * ido_playback_menu_item_new_from_model (GMenuItem *item, GActionGroup *actions) { IdoPlaybackMenuItem *widget; gchar *play_action; widget = g_object_new (IDO_TYPE_PLAYBACK_MENU_ITEM, NULL); widget->action_group = g_object_ref (actions); g_signal_connect (actions, "action-state-changed", G_CALLBACK (ido_playback_menu_item_action_state_changed), widget); g_signal_connect (actions, "action-added", G_CALLBACK (ido_playback_menu_item_action_added), widget); g_signal_connect (actions, "action-removed", G_CALLBACK (ido_playback_menu_item_action_removed), widget); g_menu_item_get_attribute (item, "x-canonical-play-action", "s", &widget->button_actions[BUTTON_PLAYPAUSE]); g_menu_item_get_attribute (item, "x-canonical-next-action", "s", &widget->button_actions[BUTTON_NEXT]); g_menu_item_get_attribute (item, "x-canonical-previous-action", "s", &widget->button_actions[BUTTON_PREVIOUS]); play_action = widget->button_actions[BUTTON_PLAYPAUSE]; if (play_action && g_action_group_has_action (actions, play_action)) ido_playback_menu_item_action_added (actions, play_action, widget); return GTK_MENU_ITEM (widget); } /* * Drawing */ typedef struct { double r; double g; double b; } CairoColorRGB; static void draw_gradient (cairo_t* cr, double x, double y, double w, double r, double* rgba_start, double* rgba_end) { cairo_pattern_t* pattern = NULL; cairo_move_to (cr, x, y); cairo_line_to (cr, x + w - 2.0f * r, y); cairo_arc (cr, x + w - 2.0f * r, y + r, r, -90.0f * G_PI / 180.0f, 90.0f * G_PI / 180.0f); cairo_line_to (cr, x, y + 2.0f * r); cairo_arc (cr, x, y + r, r, 90.0f * G_PI / 180.0f, 270.0f * G_PI / 180.0f); cairo_close_path (cr); pattern = cairo_pattern_create_linear (x, y, x, y + 2.0f * r); cairo_pattern_add_color_stop_rgba (pattern, 0.0f, rgba_start[0], rgba_start[1], rgba_start[2], rgba_start[3]); cairo_pattern_add_color_stop_rgba (pattern, 1.0f, rgba_end[0], rgba_end[1], rgba_end[2], rgba_end[3]); cairo_set_source (cr, pattern); cairo_fill (cr); cairo_pattern_destroy (pattern); } static void draw_circle (cairo_t* cr, double x, double y, double r, double* rgba_start, double* rgba_end) { cairo_pattern_t* pattern = NULL; cairo_move_to (cr, x, y); cairo_arc (cr, x + r, y + r, r, 0.0f * G_PI / 180.0f, 360.0f * G_PI / 180.0f); pattern = cairo_pattern_create_linear (x, y, x, y + 2.0f * r); cairo_pattern_add_color_stop_rgba (pattern, 0.0f, rgba_start[0], rgba_start[1], rgba_start[2], rgba_start[3]); cairo_pattern_add_color_stop_rgba (pattern, 1.0f, rgba_end[0], rgba_end[1], rgba_end[2], rgba_end[3]); cairo_set_source (cr, pattern); cairo_fill (cr); cairo_pattern_destroy (pattern); } static void _setup (cairo_t** cr, cairo_surface_t** surf, gint width, gint height) { if (!cr || !surf) return; *surf = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); *cr = cairo_create (*surf); cairo_scale (*cr, 1.0f, 1.0f); cairo_set_operator (*cr, CAIRO_OPERATOR_CLEAR); cairo_paint (*cr); cairo_set_operator (*cr, CAIRO_OPERATOR_OVER); } static void _mask_prev (cairo_t* cr, double x, double y, double tri_width, double tri_height, double tri_offset) { if (!cr) return; cairo_move_to (cr, x, y + tri_height / 2.0f); cairo_line_to (cr, x + tri_width, y); cairo_line_to (cr, x + tri_width, y + tri_height); x += tri_offset; cairo_move_to (cr, x, y + tri_height / 2.0f); cairo_line_to (cr, x + tri_width, y); cairo_line_to (cr, x + tri_width, y + tri_height); x -= tri_offset; cairo_rectangle (cr, x, y, 2.5f, tri_height); cairo_close_path (cr); } static void _mask_next (cairo_t* cr, double x, double y, double tri_width, double tri_height, double tri_offset) { if (!cr) return; cairo_move_to (cr, x, y); cairo_line_to (cr, x + tri_width, y + tri_height / 2.0f); cairo_line_to (cr, x, y + tri_height); x += tri_offset; cairo_move_to (cr, x, y); cairo_line_to (cr, x + tri_width, y + tri_height / 2.0f); cairo_line_to (cr, x, y + tri_height); x -= tri_offset; x += 2.0f * tri_width - tri_offset - 1.0f; cairo_rectangle (cr, x, y, 2.5f, tri_height); cairo_close_path (cr); } static void _mask_pause (cairo_t* cr, double x, double y, double bar_width, double bar_height, double bar_offset) { if (!cr) return; cairo_set_line_width (cr, bar_width); cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); x += bar_width; y += bar_width; cairo_move_to (cr, x, y); cairo_line_to (cr, x, y + bar_height); cairo_move_to (cr, x + bar_offset, y); cairo_line_to (cr, x + bar_offset, y + bar_height); } static void _mask_play (cairo_t* cr, double x, double y, double tri_width, double tri_height) { if (!cr) return; cairo_move_to (cr, x, y); cairo_line_to (cr, x + tri_width, y + tri_height / 2.0f); cairo_line_to (cr, x, y + tri_height); cairo_close_path (cr); } static void _fill (cairo_t* cr, double x_start, double y_start, double x_end, double y_end, double* rgba_start, double* rgba_end, gboolean stroke) { cairo_pattern_t* pattern = NULL; if (!cr || !rgba_start || !rgba_end) return; pattern = cairo_pattern_create_linear (x_start, y_start, x_end, y_end); cairo_pattern_add_color_stop_rgba (pattern, 0.0f, rgba_start[0], rgba_start[1], rgba_start[2], rgba_start[3]); cairo_pattern_add_color_stop_rgba (pattern, 1.0f, rgba_end[0], rgba_end[1], rgba_end[2], rgba_end[3]); cairo_set_source (cr, pattern); if (stroke) cairo_stroke (cr); else cairo_fill (cr); cairo_pattern_destroy (pattern); } static void _finalize (cairo_t* cr, cairo_t** cr_surf, cairo_surface_t** surf, double x, double y) { if (!cr || !cr_surf || !surf) return; cairo_set_source_surface (cr, *surf, x, y); cairo_paint (cr); cairo_surface_destroy (*surf); cairo_destroy (*cr_surf); } static void _finalize_repaint (cairo_t* cr, cairo_t** cr_surf, cairo_surface_t** surf, double x, double y, int repaints) { if (!cr || !cr_surf || !surf) return; while (repaints > 0) { cairo_set_source_surface (cr, *surf, x, y); cairo_paint (cr); repaints--; } cairo_surface_destroy (*surf); cairo_destroy (*cr_surf); } static void _color_rgb_to_hls (gdouble *r, gdouble *g, gdouble *b) { gdouble min; gdouble max; gdouble red; gdouble green; gdouble blue; gdouble h = 0; gdouble l; gdouble s; gdouble delta; red = *r; green = *g; blue = *b; if (red > green) { if (red > blue) max = red; else max = blue; if (green < blue) min = green; else min = blue; } else { if (green > blue) max = green; else max = blue; if (red < blue) min = red; else min = blue; } l = (max+min)/2; if (fabs (max-min) < 0.0001) { h = 0; s = 0; } else { if (l <= 0.5) s = (max-min)/(max+min); else s = (max-min)/(2-max-min); delta = (max -min) != 0 ? (max -min) : 1; if(delta == 0) delta = 1; if (red == max) h = (green-blue)/delta; else if (green == max) h = 2+(blue-red)/delta; else if (blue == max) h = 4+(red-green)/delta; h *= 60; if (h < 0.0) h += 360; } *r = h; *g = l; *b = s; } static void _color_hls_to_rgb (gdouble *h, gdouble *l, gdouble *s) { gdouble hue; gdouble lightness; gdouble saturation; gdouble m1, m2; gdouble r, g, b; lightness = *l; saturation = *s; if (lightness <= 0.5) m2 = lightness*(1+saturation); else m2 = lightness+saturation-lightness*saturation; m1 = 2*lightness-m2; if (saturation == 0) { *h = lightness; *l = lightness; *s = lightness; } else { hue = *h+120; while (hue > 360) hue -= 360; while (hue < 0) hue += 360; if (hue < 60) r = m1+(m2-m1)*hue/60; else if (hue < 180) r = m2; else if (hue < 240) r = m1+(m2-m1)*(240-hue)/60; else r = m1; hue = *h; while (hue > 360) hue -= 360; while (hue < 0) hue += 360; if (hue < 60) g = m1+(m2-m1)*hue/60; else if (hue < 180) g = m2; else if (hue < 240) g = m1+(m2-m1)*(240-hue)/60; else g = m1; hue = *h-120; while (hue > 360) hue -= 360; while (hue < 0) hue += 360; if (hue < 60) b = m1+(m2-m1)*hue/60; else if (hue < 180) b = m2; else if (hue < 240) b = m1+(m2-m1)*(240-hue)/60; else b = m1; *h = r; *l = g; *s = b; } } static void _color_shade (const CairoColorRGB *a, float k, CairoColorRGB *b) { double red; double green; double blue; red = a->r; green = a->g; blue = a->b; if (k == 1.0) { b->r = red; b->g = green; b->b = blue; return; } _color_rgb_to_hls (&red, &green, &blue); green *= k; if (green > 1.0) green = 1.0; else if (green < 0.0) green = 0.0; blue *= k; if (blue > 1.0) blue = 1.0; else if (blue < 0.0) blue = 0.0; _color_hls_to_rgb (&red, &green, &blue); b->r = red; b->g = green; b->b = blue; } static inline void _blurinner (guchar* pixel, gint* zR, gint* zG, gint* zB, gint* zA, gint alpha, gint aprec, gint zprec) { gint R; gint G; gint B; guchar A; R = *pixel; G = *(pixel + 1); B = *(pixel + 2); A = *(pixel + 3); *zR += (alpha * ((R << zprec) - *zR)) >> aprec; *zG += (alpha * ((G << zprec) - *zG)) >> aprec; *zB += (alpha * ((B << zprec) - *zB)) >> aprec; *zA += (alpha * ((A << zprec) - *zA)) >> aprec; *pixel = *zR >> zprec; *(pixel + 1) = *zG >> zprec; *(pixel + 2) = *zB >> zprec; *(pixel + 3) = *zA >> zprec; } static inline void _blurrow (guchar* pixels, gint width, gint height, gint channels, gint line, gint alpha, gint aprec, gint zprec) { gint zR; gint zG; gint zB; gint zA; gint index; guchar* scanline; scanline = &(pixels[line * width * channels]); zR = *scanline << zprec; zG = *(scanline + 1) << zprec; zB = *(scanline + 2) << zprec; zA = *(scanline + 3) << zprec; for (index = 0; index < width; index ++) _blurinner (&scanline[index * channels], &zR, &zG, &zB, &zA, alpha, aprec, zprec); for (index = width - 2; index >= 0; index--) _blurinner (&scanline[index * channels], &zR, &zG, &zB, &zA, alpha, aprec, zprec); } static inline void _blurcol (guchar* pixels, gint width, gint height, gint channels, gint x, gint alpha, gint aprec, gint zprec) { gint zR; gint zG; gint zB; gint zA; gint index; guchar* ptr; ptr = pixels; ptr += x * channels; zR = *((guchar*) ptr ) << zprec; zG = *((guchar*) ptr + 1) << zprec; zB = *((guchar*) ptr + 2) << zprec; zA = *((guchar*) ptr + 3) << zprec; for (index = width; index < (height - 1) * width; index += width) _blurinner ((guchar*) &ptr[index * channels], &zR, &zG, &zB, &zA, alpha, aprec, zprec); for (index = (height - 2) * width; index >= 0; index -= width) _blurinner ((guchar*) &ptr[index * channels], &zR, &zG, &zB, &zA, alpha, aprec, zprec); } static void _expblur (guchar* pixels, gint width, gint height, gint channels, gint radius, gint aprec, gint zprec) { gint alpha; gint row = 0; gint col = 0; if (radius < 1) return; // calculate the alpha such that 90% of // the kernel is within the radius. // (Kernel extends to infinity) alpha = (gint) ((1 << aprec) * (1.0f - expf (-2.3f / (radius + 1.f)))); for (; row < height; row++) _blurrow (pixels, width, height, channels, row, alpha, aprec, zprec); for(; col < width; col++) _blurcol (pixels, width, height, channels, col, alpha, aprec, zprec); return; } static void _surface_blur (cairo_surface_t* surface, guint radius) { guchar* pixels; guint width; guint height; cairo_format_t format; // before we mess with the surface execute any pending drawing cairo_surface_flush (surface); pixels = cairo_image_surface_get_data (surface); width = cairo_image_surface_get_width (surface); height = cairo_image_surface_get_height (surface); format = cairo_image_surface_get_format (surface); switch (format) { case CAIRO_FORMAT_ARGB32: _expblur (pixels, width, height, 4, radius, 16, 7); break; case CAIRO_FORMAT_RGB24: _expblur (pixels, width, height, 3, radius, 16, 7); break; case CAIRO_FORMAT_A8: _expblur (pixels, width, height, 1, radius, 16, 7); break; default : // do nothing break; } // inform cairo we altered the surfaces contents cairo_surface_mark_dirty (surface); } static gboolean ido_playback_menu_item_draw (GtkWidget* button, cairo_t *cr) { IdoPlaybackMenuItem *item = IDO_PLAYBACK_MENU_ITEM (button); GtkAllocation alloc; gint X; gint abs_pause_x; gint abs_prev_x; gint abs_next_x; g_return_val_if_fail(IDO_IS_PLAYBACK_MENU_ITEM (button), FALSE); g_return_val_if_fail(cr != NULL, FALSE); cairo_surface_t* surf = NULL; cairo_t* cr_surf = NULL; GtkStyle *style; CairoColorRGB bg_color, fg_color, bg_selected, bg_prelight; CairoColorRGB color_middle[2], color_middle_prelight[2], color_outer[2], color_outer_prelight[2], color_play_outer[2], color_play_outer_prelight[2], color_button[4], color_button_shadow, color_inner[2], color_inner_compressed[2]; /* Use the menu's style instead of that of the menuitem ('button' is a * menuitem that is packed in a menu directly). The menuitem's style * can't be used due to a change in light-themes (lp #1130183). * Menuitems now have a transparent background, which confuses * GtkStyle. * * This is a workaround until this code gets refactored to use * GtkStyleContext. */ style = gtk_widget_get_style (gtk_widget_get_parent (button)); bg_color.r = style->bg[0].red/65535.0; bg_color.g = style->bg[0].green/65535.0; bg_color.b = style->bg[0].blue/65535.0; bg_prelight.r = style->bg[GTK_STATE_PRELIGHT].red/65535.0; bg_prelight.g = style->bg[GTK_STATE_PRELIGHT].green/65535.0; bg_prelight.b = style->bg[GTK_STATE_PRELIGHT].blue/65535.0; bg_selected.r = style->bg[GTK_STATE_SELECTED].red/65535.0; bg_selected.g = style->bg[GTK_STATE_SELECTED].green/65535.0; bg_selected.b = style->bg[GTK_STATE_SELECTED].blue/65535.0; fg_color.r = style->fg[0].red/65535.0; fg_color.g = style->fg[0].green/65535.0; fg_color.b = style->fg[0].blue/65535.0; _color_shade (&bg_color, MIDDLE_START_SHADE, &color_middle[0]); _color_shade (&bg_color, MIDDLE_END_SHADE, &color_middle[1]); _color_shade (&bg_prelight, MIDDLE_START_SHADE, &color_middle_prelight[0]); _color_shade (&bg_prelight, MIDDLE_END_SHADE, &color_middle_prelight[1]); _color_shade (&bg_color, OUTER_START_SHADE, &color_outer[0]); _color_shade (&bg_color, OUTER_END_SHADE, &color_outer[1]); _color_shade (&bg_prelight, OUTER_START_SHADE, &color_outer_prelight[0]); _color_shade (&bg_prelight, OUTER_END_SHADE, &color_outer_prelight[1]); _color_shade (&bg_color, OUTER_PLAY_START_SHADE, &color_play_outer[0]); _color_shade (&bg_color, OUTER_PLAY_END_SHADE, &color_play_outer[1]); _color_shade (&bg_prelight, OUTER_PLAY_START_SHADE, &color_play_outer_prelight[0]); _color_shade (&bg_prelight, OUTER_PLAY_END_SHADE, &color_play_outer_prelight[1]); _color_shade (&bg_color, INNER_START_SHADE, &color_inner[0]); _color_shade (&bg_color, INNER_END_SHADE, &color_inner[1]); _color_shade (&fg_color, BUTTON_START_SHADE, &color_button[0]); _color_shade (&fg_color, BUTTON_END_SHADE, &color_button[1]); _color_shade (&bg_color, BUTTON_SHADOW_SHADE, &color_button[2]); _color_shade (&bg_color, SHADOW_BUTTON_SHADE, &color_button_shadow); _color_shade (&bg_selected, 1.0, &color_button[3]); _color_shade (&bg_color, INNER_COMPRESSED_START_SHADE, &color_inner_compressed[0]); _color_shade (&bg_color, INNER_COMPRESSED_END_SHADE, &color_inner_compressed[1]); double MIDDLE_END[] = {color_middle[0].r, color_middle[0].g, color_middle[0].b, 1.0f}; double MIDDLE_START[] = {color_middle[1].r, color_middle[1].g, color_middle[1].b, 1.0f}; double MIDDLE_END_PRELIGHT[] = {color_middle_prelight[0].r, color_middle_prelight[0].g, color_middle_prelight[0].b, 1.0f}; double MIDDLE_START_PRELIGHT[] = {color_middle_prelight[1].r, color_middle_prelight[1].g, color_middle_prelight[1].b, 1.0f}; double OUTER_END[] = {color_outer[0].r, color_outer[0].g, color_outer[0].b, 1.0f}; double OUTER_START[] = {color_outer[1].r, color_outer[1].g, color_outer[1].b, 1.0f}; double OUTER_END_PRELIGHT[] = {color_outer_prelight[0].r, color_outer_prelight[0].g, color_outer_prelight[0].b, 1.0f}; double OUTER_START_PRELIGHT[] = {color_outer_prelight[1].r, color_outer_prelight[1].g, color_outer_prelight[1].b, 1.0f}; double SHADOW_BUTTON[] = {color_button_shadow.r, color_button_shadow.g, color_button_shadow.b, 0.3f}; double OUTER_PLAY_END[] = {color_play_outer[0].r, color_play_outer[0].g, color_play_outer[0].b, 1.0f}; double OUTER_PLAY_START[] = {color_play_outer[1].r, color_play_outer[1].g, color_play_outer[1].b, 1.0f}; double OUTER_PLAY_END_PRELIGHT[] = {color_play_outer_prelight[0].r, color_play_outer_prelight[0].g, color_play_outer_prelight[0].b, 1.0f}; double OUTER_PLAY_START_PRELIGHT[] = {color_play_outer_prelight[1].r, color_play_outer_prelight[1].g, color_play_outer_prelight[1].b, 1.0f}; double BUTTON_END[] = {color_button[0].r, color_button[0].g, color_button[0].b, 1.0f}; double BUTTON_START[] = {color_button[1].r, color_button[1].g, color_button[1].b, 1.0f}; double BUTTON_SHADOW[] = {color_button[2].r, color_button[2].g, color_button[2].b, 0.75f}; double BUTTON_SHADOW_FOCUS[] = {color_button[3].r, color_button[3].g, color_button[3].b, 1.0f}; double INNER_COMPRESSED_END[] = {color_inner_compressed[1].r, color_inner_compressed[1].g, color_inner_compressed[1].b, 1.0f}; double INNER_COMPRESSED_START[] = {color_inner_compressed[0].r, color_inner_compressed[0].g, color_inner_compressed[0].b, 1.0f}; gtk_widget_get_allocation (button, &alloc); X = alloc.x + (alloc.width - RECT_WIDTH) / 2 + OUTER_RADIUS; abs_pause_x = X + PAUSE_X; abs_prev_x = X + PREV_X; abs_next_x = X + NEXT_X; draw_gradient (cr, X, Y, RECT_WIDTH, OUTER_RADIUS, OUTER_START, OUTER_END); draw_gradient (cr, X, Y + 1, RECT_WIDTH - 2, MIDDLE_RADIUS, MIDDLE_START, MIDDLE_END); draw_gradient (cr, X, Y + 2, RECT_WIDTH - 4, MIDDLE_RADIUS, MIDDLE_START, MIDDLE_END); if(item->cur_pushed_button == BUTTON_PREVIOUS) { draw_gradient (cr, X, Y, RECT_WIDTH/2, OUTER_RADIUS, OUTER_END, OUTER_START); draw_gradient (cr, X, Y + 1, RECT_WIDTH/2, MIDDLE_RADIUS, INNER_COMPRESSED_START, INNER_COMPRESSED_END); draw_gradient (cr, X, Y + 2, RECT_WIDTH/2, MIDDLE_RADIUS, INNER_COMPRESSED_START, INNER_COMPRESSED_END); } else if(item->cur_pushed_button == BUTTON_NEXT) { draw_gradient (cr, RECT_WIDTH / 2 + X, Y, RECT_WIDTH/2, OUTER_RADIUS, OUTER_END, OUTER_START); draw_gradient (cr, RECT_WIDTH / 2 + X, Y + 1, (RECT_WIDTH - 4.5)/2, MIDDLE_RADIUS, INNER_COMPRESSED_START, INNER_COMPRESSED_END); draw_gradient (cr, RECT_WIDTH / 2 + X, Y + 2, (RECT_WIDTH - 7)/2, MIDDLE_RADIUS, INNER_COMPRESSED_START, INNER_COMPRESSED_END); } else if (item->cur_hover_button == BUTTON_PREVIOUS) { draw_gradient (cr, X, Y, RECT_WIDTH/2, OUTER_RADIUS, OUTER_START_PRELIGHT, OUTER_END_PRELIGHT); draw_gradient (cr, X, Y + 1, RECT_WIDTH/2, MIDDLE_RADIUS, MIDDLE_START_PRELIGHT, MIDDLE_END_PRELIGHT); draw_gradient (cr, X, Y + 2, RECT_WIDTH/2, MIDDLE_RADIUS, MIDDLE_START_PRELIGHT, MIDDLE_END_PRELIGHT); } else if (item->cur_hover_button == BUTTON_NEXT) { draw_gradient (cr, RECT_WIDTH / 2 + X, Y, RECT_WIDTH/2, OUTER_RADIUS, OUTER_START_PRELIGHT, OUTER_END_PRELIGHT); draw_gradient (cr, RECT_WIDTH / 2 + X, Y + 1, (RECT_WIDTH - 4.5)/2, MIDDLE_RADIUS, MIDDLE_START_PRELIGHT, MIDDLE_END_PRELIGHT); draw_gradient (cr, RECT_WIDTH / 2 + X, Y + 2, (RECT_WIDTH - 7)/2, MIDDLE_RADIUS, MIDDLE_START_PRELIGHT, MIDDLE_END_PRELIGHT); } // play/pause shadow if(item->cur_pushed_button != BUTTON_PLAYPAUSE) { cairo_save (cr); cairo_rectangle (cr, X, Y, RECT_WIDTH, MIDDLE_RADIUS*2); cairo_clip (cr); draw_circle (cr, X + RECT_WIDTH / 2.0f - 2.0f * OUTER_RADIUS - 5.5f - 1.0f, Y - ((CIRCLE_RADIUS - OUTER_RADIUS)) - 1.0f, CIRCLE_RADIUS + 1.0f, SHADOW_BUTTON, SHADOW_BUTTON); cairo_restore (cr); } // play/pause button if(item->cur_pushed_button == BUTTON_PLAYPAUSE) { draw_circle (cr, X + RECT_WIDTH / 2.0f - 2.0f * OUTER_RADIUS - 5.5f, Y - ((CIRCLE_RADIUS - OUTER_RADIUS)) , CIRCLE_RADIUS, OUTER_PLAY_END, OUTER_PLAY_START); draw_circle (cr, X + RECT_WIDTH / 2.0f - 2.0f * OUTER_RADIUS - 5.5f + 1.25f, Y - ((CIRCLE_RADIUS - OUTER_RADIUS)) + 1.25f, CIRCLE_RADIUS - 1.25, INNER_COMPRESSED_START, INNER_COMPRESSED_END); } else if (item->cur_hover_button == BUTTON_PLAYPAUSE) { /* this subtle offset is to fix alpha borders, should be removed once this draw routine will be refactored */ draw_circle (cr, X + RECT_WIDTH / 2.0f - 2.0f * OUTER_RADIUS - 5.5f + 0.1, Y - ((CIRCLE_RADIUS - OUTER_RADIUS)) + 0.1, CIRCLE_RADIUS - 0.1, OUTER_PLAY_START_PRELIGHT, OUTER_PLAY_END_PRELIGHT); draw_circle (cr, X + RECT_WIDTH / 2.0f - 2.0f * OUTER_RADIUS - 5.5f + 1.25f, Y - ((CIRCLE_RADIUS - OUTER_RADIUS)) + 1.25f, CIRCLE_RADIUS - 1.25, MIDDLE_START_PRELIGHT, MIDDLE_END_PRELIGHT); } else { draw_circle (cr, X + RECT_WIDTH / 2.0f - 2.0f * OUTER_RADIUS - 5.5f, Y - ((CIRCLE_RADIUS - OUTER_RADIUS)), CIRCLE_RADIUS, OUTER_PLAY_START, OUTER_PLAY_END); draw_circle (cr, X + RECT_WIDTH / 2.0f - 2.0f * OUTER_RADIUS - 5.5f + 1.25f, Y - ((CIRCLE_RADIUS - OUTER_RADIUS)) + 1.25f, CIRCLE_RADIUS - 1.25, MIDDLE_START, MIDDLE_END); } // draw previous-button drop-shadow if ((item->cur_pushed_button == BUTTON_PREVIOUS && item->keyboard_activated) || item->cur_hover_button == BUTTON_PREVIOUS) { _setup (&cr_surf, &surf, PREV_WIDTH+6, PREV_HEIGHT+6); _mask_prev (cr_surf, (PREV_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, (PREV_HEIGHT - TRI_HEIGHT) / 2.0f, TRI_WIDTH, TRI_HEIGHT, TRI_OFFSET); _fill (cr_surf, (PREV_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, (PREV_HEIGHT - TRI_HEIGHT) / 2.0f, (PREV_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, (double) TRI_HEIGHT, BUTTON_SHADOW_FOCUS, BUTTON_SHADOW_FOCUS, FALSE); _surface_blur (surf, 3); _finalize_repaint (cr, &cr_surf, &surf, abs_prev_x, PREV_Y + 0.5f, 3); } else { _setup (&cr_surf, &surf, PREV_WIDTH, PREV_HEIGHT); _mask_prev (cr_surf, (PREV_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, (PREV_HEIGHT - TRI_HEIGHT) / 2.0f, TRI_WIDTH, TRI_HEIGHT, TRI_OFFSET); _fill (cr_surf, (PREV_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, (PREV_HEIGHT - TRI_HEIGHT) / 2.0f, (PREV_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, (double) TRI_HEIGHT, BUTTON_SHADOW, BUTTON_SHADOW, FALSE); _surface_blur (surf, 1); _finalize (cr, &cr_surf, &surf, abs_prev_x, PREV_Y + 1.0f); } // draw previous-button _setup (&cr_surf, &surf, PREV_WIDTH, PREV_HEIGHT); _mask_prev (cr_surf, (PREV_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, (PREV_HEIGHT - TRI_HEIGHT) / 2.0f, TRI_WIDTH, TRI_HEIGHT, TRI_OFFSET); _fill (cr_surf, (PREV_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, (PREV_HEIGHT - TRI_HEIGHT) / 2.0f, (PREV_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, (double) TRI_HEIGHT, BUTTON_START, BUTTON_END, FALSE); _finalize (cr, &cr_surf, &surf, abs_prev_x, PREV_Y); // draw next-button drop-shadow if ((item->cur_pushed_button == BUTTON_NEXT && item->keyboard_activated) || item->cur_hover_button == BUTTON_NEXT) { _setup (&cr_surf, &surf, NEXT_WIDTH+6, NEXT_HEIGHT+6); _mask_next (cr_surf, (NEXT_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, (NEXT_HEIGHT - TRI_HEIGHT) / 2.0f, TRI_WIDTH, TRI_HEIGHT, TRI_OFFSET); _fill (cr_surf, (NEXT_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, (NEXT_HEIGHT - TRI_HEIGHT) / 2.0f, (NEXT_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, (double) TRI_HEIGHT, BUTTON_SHADOW_FOCUS, BUTTON_SHADOW_FOCUS, FALSE); _surface_blur (surf, 3); _finalize_repaint (cr, &cr_surf, &surf, abs_next_x, NEXT_Y + 0.5f, 3); } else { _setup (&cr_surf, &surf, NEXT_WIDTH, NEXT_HEIGHT); _mask_next (cr_surf, (NEXT_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, (NEXT_HEIGHT - TRI_HEIGHT) / 2.0f, TRI_WIDTH, TRI_HEIGHT, TRI_OFFSET); _fill (cr_surf, (NEXT_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, (NEXT_HEIGHT - TRI_HEIGHT) / 2.0f, (NEXT_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, (double) TRI_HEIGHT, BUTTON_SHADOW, BUTTON_SHADOW, FALSE); _surface_blur (surf, 1); _finalize (cr, &cr_surf, &surf, abs_next_x, NEXT_Y + 1.0f); } // draw next-button _setup (&cr_surf, &surf, NEXT_WIDTH, NEXT_HEIGHT); _mask_next (cr_surf, (NEXT_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, (NEXT_HEIGHT - TRI_HEIGHT) / 2.0f, TRI_WIDTH, TRI_HEIGHT, TRI_OFFSET); _fill (cr_surf, (NEXT_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, (NEXT_HEIGHT - TRI_HEIGHT) / 2.0f, (NEXT_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, (double) TRI_HEIGHT, BUTTON_START, BUTTON_END, FALSE); _finalize (cr, &cr_surf, &surf, abs_next_x, NEXT_Y); // draw pause-button drop-shadow if (item->current_state == STATE_PLAYING) { if (item->has_focus && (item->cur_hover_button == BUTTON_NONE || item->cur_hover_button == BUTTON_PLAYPAUSE) && (item->cur_pushed_button == BUTTON_NONE || item->cur_pushed_button == BUTTON_PLAYPAUSE)) { _setup (&cr_surf, &surf, PAUSE_WIDTH+6, PAUSE_HEIGHT+6); _mask_pause (cr_surf, (PAUSE_WIDTH - (2.0f * BAR_WIDTH + BAR_OFFSET)) / 2.0f, (PAUSE_HEIGHT - BAR_HEIGHT) / 2.0f, BAR_WIDTH, BAR_HEIGHT - 2.0f * BAR_WIDTH, BAR_OFFSET); _fill (cr_surf, (PAUSE_WIDTH - (2.0f * BAR_WIDTH + BAR_OFFSET)) / 2.0f, (PAUSE_HEIGHT - BAR_HEIGHT) / 2.0f, (PAUSE_WIDTH - (2.0f * BAR_WIDTH + BAR_OFFSET)) / 2.0f, (double) BAR_HEIGHT, BUTTON_SHADOW_FOCUS, BUTTON_SHADOW_FOCUS, TRUE); _surface_blur (surf, 3); _finalize_repaint (cr, &cr_surf, &surf, abs_pause_x, PAUSE_Y + 0.5f, 3); } else { _setup (&cr_surf, &surf, PAUSE_WIDTH, PAUSE_HEIGHT); _mask_pause (cr_surf, (PAUSE_WIDTH - (2.0f * BAR_WIDTH + BAR_OFFSET)) / 2.0f, (PAUSE_HEIGHT - BAR_HEIGHT) / 2.0f, BAR_WIDTH, BAR_HEIGHT - 2.0f * BAR_WIDTH, BAR_OFFSET); _fill (cr_surf, (PAUSE_WIDTH - (2.0f * BAR_WIDTH + BAR_OFFSET)) / 2.0f, (PAUSE_HEIGHT - BAR_HEIGHT) / 2.0f, (PAUSE_WIDTH - (2.0f * BAR_WIDTH + BAR_OFFSET)) / 2.0f, (double) BAR_HEIGHT, BUTTON_SHADOW, BUTTON_SHADOW, TRUE); _surface_blur (surf, 1); _finalize (cr, &cr_surf, &surf, abs_pause_x, PAUSE_Y + 1.0f); } // draw pause-button _setup (&cr_surf, &surf, PAUSE_WIDTH, PAUSE_HEIGHT); _mask_pause (cr_surf, (PAUSE_WIDTH - (2.0f * BAR_WIDTH + BAR_OFFSET)) / 2.0f, (PAUSE_HEIGHT - BAR_HEIGHT) / 2.0f, BAR_WIDTH, BAR_HEIGHT - 2.0f * BAR_WIDTH, BAR_OFFSET); _fill (cr_surf, (PAUSE_WIDTH - (2.0f * BAR_WIDTH + BAR_OFFSET)) / 2.0f, (PAUSE_HEIGHT - BAR_HEIGHT) / 2.0f, (PAUSE_WIDTH - (2.0f * BAR_WIDTH + BAR_OFFSET)) / 2.0f, (double) BAR_HEIGHT, BUTTON_START, BUTTON_END, TRUE); _finalize (cr, &cr_surf, &surf, abs_pause_x, PAUSE_Y); } else if (item->current_state == STATE_PAUSED) { if (item->has_focus && (item->cur_hover_button == BUTTON_NONE || item->cur_hover_button == BUTTON_PLAYPAUSE) && (item->cur_pushed_button == BUTTON_NONE || item->cur_pushed_button == BUTTON_PLAYPAUSE)) { _setup (&cr_surf, &surf, PLAY_WIDTH+6, PLAY_HEIGHT+6); _mask_play (cr_surf, PLAY_PADDING, PLAY_PADDING, PLAY_WIDTH - (2*PLAY_PADDING), PLAY_HEIGHT - (2*PLAY_PADDING)); _fill (cr_surf, PLAY_PADDING, PLAY_PADDING, PLAY_WIDTH - (2*PLAY_PADDING), PLAY_HEIGHT - (2*PLAY_PADDING), BUTTON_SHADOW_FOCUS, BUTTON_SHADOW_FOCUS, FALSE); _surface_blur (surf, 3); _finalize_repaint (cr, &cr_surf, &surf, abs_pause_x-0.5f, PAUSE_Y + 0.5f, 3); } else { _setup (&cr_surf, &surf, PLAY_WIDTH, PLAY_HEIGHT); _mask_play (cr_surf, PLAY_PADDING, PLAY_PADDING, PLAY_WIDTH - (2*PLAY_PADDING), PLAY_HEIGHT - (2*PLAY_PADDING)); _fill (cr_surf, PLAY_PADDING, PLAY_PADDING, PLAY_WIDTH - (2*PLAY_PADDING), PLAY_HEIGHT - (2*PLAY_PADDING), BUTTON_SHADOW, BUTTON_SHADOW, FALSE); _surface_blur (surf, 1); _finalize (cr, &cr_surf, &surf, abs_pause_x-0.75f, PAUSE_Y + 1.0f); } // draw play-button _setup (&cr_surf, &surf, PLAY_WIDTH, PLAY_HEIGHT); cairo_set_line_width (cr, 10.5); cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); _mask_play (cr_surf, PLAY_PADDING, PLAY_PADDING, PLAY_WIDTH - (2*PLAY_PADDING), PLAY_HEIGHT - (2*PLAY_PADDING)); _fill (cr_surf, PLAY_PADDING, PLAY_PADDING, PLAY_WIDTH - (2*PLAY_PADDING), PLAY_HEIGHT - (2*PLAY_PADDING), BUTTON_START, BUTTON_END, FALSE); _finalize (cr, &cr_surf, &surf, abs_pause_x-0.5f, PAUSE_Y); } else if (item->current_state == STATE_LAUNCHING) { // the spinner is not aligned, why? because the play button has odd width/height numbers gtk_render_activity (gtk_widget_get_style_context (button), cr, 106, 6, 30, 30); } return FALSE; } ./src/idotimestampmenuitem.c0000644000004100000410000001410214320114711016431 0ustar www-datawww-data/* * Copyright 2013 Canonical Ltd. * * Authors: * Charles Kerr * Ted Gould * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include /* strstr() */ #include #include "idoactionhelper.h" #include "idotimestampmenuitem.h" enum { PROP_0, PROP_FORMAT, PROP_DATE_TIME, PROP_LAST }; static GParamSpec *properties[PROP_LAST]; struct _IdoTimeStampMenuItemPrivate { char * format; GDateTime * date_time; }; typedef IdoTimeStampMenuItemPrivate priv_t; G_DEFINE_TYPE (IdoTimeStampMenuItem, ido_time_stamp_menu_item, IDO_TYPE_BASIC_MENU_ITEM); /*** **** GObject Virtual Functions ***/ static void my_get_property (GObject * o, guint property_id, GValue * v, GParamSpec * pspec) { IdoTimeStampMenuItem * self = IDO_TIME_STAMP_MENU_ITEM (o); priv_t * p = self->priv; switch (property_id) { case PROP_FORMAT: g_value_set_string (v, p->format); break; case PROP_DATE_TIME: g_value_set_boxed (v, p->date_time); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); break; } } static void my_set_property (GObject * o, guint property_id, const GValue * v, GParamSpec * pspec) { IdoTimeStampMenuItem * self = IDO_TIME_STAMP_MENU_ITEM (o); switch (property_id) { case PROP_FORMAT: ido_time_stamp_menu_item_set_format (self, g_value_get_string (v)); break; case PROP_DATE_TIME: ido_time_stamp_menu_item_set_date_time (self, g_value_get_boxed (v)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); break; } } static void my_dispose (GObject * object) { IdoTimeStampMenuItem * self = IDO_TIME_STAMP_MENU_ITEM (object); priv_t * p = self->priv; g_clear_pointer (&p->date_time, g_date_time_unref); G_OBJECT_CLASS (ido_time_stamp_menu_item_parent_class)->dispose (object); } static void my_finalize (GObject * object) { IdoTimeStampMenuItem * self = IDO_TIME_STAMP_MENU_ITEM (object); priv_t * p = self->priv; g_free (p->format); G_OBJECT_CLASS (ido_time_stamp_menu_item_parent_class)->finalize (object); } /*** **** Instantiation ***/ static void ido_time_stamp_menu_item_class_init (IdoTimeStampMenuItemClass *klass) { GParamFlags prop_flags; GObjectClass * gobject_class = G_OBJECT_CLASS (klass); g_type_class_add_private (klass, sizeof (IdoTimeStampMenuItemPrivate)); gobject_class->get_property = my_get_property; gobject_class->set_property = my_set_property; gobject_class->dispose = my_dispose; gobject_class->finalize = my_finalize; prop_flags = G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS; properties[PROP_FORMAT] = g_param_spec_string ( "format", "strftime format", "strftime-style format string for the timestamp", "%F %T", prop_flags); properties[PROP_DATE_TIME] = g_param_spec_boxed ( "date-time", "Date-Time", "GDateTime specifying the time to render", G_TYPE_DATE_TIME, prop_flags); g_object_class_install_properties (gobject_class, PROP_LAST, properties); } static void ido_time_stamp_menu_item_init (IdoTimeStampMenuItem *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, IDO_TYPE_TIME_STAMP_MENU_ITEM, IdoTimeStampMenuItemPrivate); } static void update_timestamp_label (IdoTimeStampMenuItem * self) { char * str; priv_t * p = self->priv; if (p->date_time && p->format) str = g_date_time_format (p->date_time, p->format); else str = NULL; ido_basic_menu_item_set_secondary_text (IDO_BASIC_MENU_ITEM (self), str); g_free (str); } /*** **** Public API ***/ /* create a new IdoTimeStampMenuItem */ GtkWidget * ido_time_stamp_menu_item_new (void) { return GTK_WIDGET (g_object_new (IDO_TYPE_TIME_STAMP_MENU_ITEM, NULL)); } /** * ido_time_stamp_menu_item_set_time: * @time: the time to be rendered in the appointment's timestamp label. * * Set the time that will be displayed in the menuitem's * right-justified timestamp label */ void ido_time_stamp_menu_item_set_date_time (IdoTimeStampMenuItem * self, GDateTime * date_time) { priv_t * p; g_return_if_fail (IDO_IS_TIME_STAMP_MENU_ITEM (self)); p = self->priv; g_clear_pointer (&p->date_time, g_date_time_unref); if (date_time != NULL) p->date_time = g_date_time_ref (date_time); update_timestamp_label (self); } /** * ido_time_stamp_menu_item_set_format: * @format: the format string used when showing the appointment's time * * Set the format string for rendering the appointment's time * in its right-justified secondary label. * * See strfrtime(3) for more information on the format string. */ void ido_time_stamp_menu_item_set_format (IdoTimeStampMenuItem * self, const char * strftime_fmt) { priv_t * p; g_return_if_fail (IDO_IS_TIME_STAMP_MENU_ITEM (self)); p = self->priv; g_free (p->format); p->format = g_strdup (strftime_fmt); update_timestamp_label (self); } const gchar * ido_time_stamp_menu_item_get_format (IdoTimeStampMenuItem * self) { g_return_val_if_fail (IDO_IS_TIME_STAMP_MENU_ITEM (self), NULL); return self->priv->format; } ./src/idoprogressmenuitem.h0000644000004100000410000000172514320114711016306 0ustar www-datawww-data/** * Copyright 2013 Canonical Ltd. * * Authors: * Charles Kerr * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifndef __IDO_PROGRESS_MENU_ITEM_H__ #define __IDO_PROGRESS_MENU_ITEM_H__ #include GtkMenuItem * ido_progress_menu_item_new_from_model (GMenuItem * menuitem, GActionGroup * actions); #endif ./src/idomenuitemfactory.c0000644000004100000410000001103314320114711016075 0ustar www-datawww-data/* * Copyright 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * * Authors: * Lars Uebernickel */ #include #include #include "idoalarmmenuitem.h" #include "idoappointmentmenuitem.h" #include "idobasicmenuitem.h" #include "idocalendarmenuitem.h" #include "idolocationmenuitem.h" #include "idoscalemenuitem.h" #include "idousermenuitem.h" #include "idomediaplayermenuitem.h" #include "idoplaybackmenuitem.h" #include "idoapplicationmenuitem.h" #include "idosourcemenuitem.h" #include "idoswitchmenuitem.h" #include "idoprogressmenuitem.h" #define IDO_TYPE_MENU_ITEM_FACTORY (ido_menu_item_factory_get_type ()) #define IDO_MENU_ITEM_FACTORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), IDO_TYPE_MENU_ITEM_FACTORY, IdoMenuItemFactory)) #define IDO_IS_MENU_ITEM_FACTORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), IDO_TYPE_MENU_ITEM_FACTORY)) typedef GObject IdoMenuItemFactory; typedef GObjectClass IdoMenuItemFactoryClass; GType ido_menu_item_factory_get_type (void); static void ido_menu_item_factory_interface_init (UbuntuMenuItemFactoryInterface *iface); G_DEFINE_TYPE_WITH_CODE (IdoMenuItemFactory, ido_menu_item_factory, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (UBUNTU_TYPE_MENU_ITEM_FACTORY, ido_menu_item_factory_interface_init) g_io_extension_point_implement (UBUNTU_MENU_ITEM_FACTORY_EXTENSION_POINT_NAME, g_define_type_id, "ido", 0);) static GtkMenuItem * ido_menu_item_factory_create_menu_item (UbuntuMenuItemFactory *factory, const gchar *type, GMenuItem *menuitem, GActionGroup *actions) { GtkMenuItem *item = NULL; if (g_str_equal (type, "indicator.user-menu-item")) item = ido_user_menu_item_new_from_model (menuitem, actions); if (g_str_equal (type, "indicator.guest-menu-item")) item = ido_guest_menu_item_new_from_model (menuitem, actions); else if (g_str_equal (type, "com.canonical.indicator.calendar")) item = ido_calendar_menu_item_new_from_model (menuitem, actions); else if (g_str_equal (type, "com.canonical.indicator.location")) item = ido_location_menu_item_new_from_model (menuitem, actions); else if (g_str_equal (type, "com.canonical.indicator.appointment")) item = ido_appointment_menu_item_new_from_model (menuitem, actions); else if (g_str_equal (type, "com.canonical.indicator.alarm")) item = ido_alarm_menu_item_new_from_model (menuitem, actions); else if (g_str_equal (type, "com.canonical.indicator.basic")) item = ido_basic_menu_item_new_from_model (menuitem, actions); else if (g_str_equal (type, "com.canonical.indicator.progress")) item = ido_progress_menu_item_new_from_model (menuitem, actions); else if (g_str_equal (type, "com.canonical.unity.slider")) item = ido_scale_menu_item_new_from_model (menuitem, actions); else if (g_str_equal (type, "com.canonical.unity.media-player")) item = ido_media_player_menu_item_new_from_model (menuitem, actions); else if (g_str_equal (type, "com.canonical.unity.playback-item")) item = ido_playback_menu_item_new_from_model (menuitem, actions); else if (g_str_equal (type, "com.canonical.application")) item = ido_application_menu_item_new_from_model (menuitem, actions); else if (g_str_equal (type, "com.canonical.indicator.messages.source")) item = ido_source_menu_item_new_from_menu_model (menuitem, actions); else if (g_str_equal (type, "com.canonical.indicator.switch")) item = ido_switch_menu_item_new_from_menu_model (menuitem, actions); return item; } static void ido_menu_item_factory_class_init (IdoMenuItemFactoryClass *class) { } static void ido_menu_item_factory_interface_init (UbuntuMenuItemFactoryInterface *iface) { iface->create_menu_item = ido_menu_item_factory_create_menu_item; } static void ido_menu_item_factory_init (IdoMenuItemFactory *factory) { } ./src/idoentrymenuitem.h0000644000004100000410000000440214320114711015576 0ustar www-datawww-data/* * Copyright 2010 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of either or both of the following licenses: * * 1) the GNU Lesser General Public License version 3, as published by the * Free Software Foundation; and/or * 2) the GNU Lesser General Public License version 2.1, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License version 3 and version 2.1 along with this program. If not, see * * * Authors: * Cody Russell */ #ifndef __IDO_ENTRY_MENU_ITEM_H__ #define __IDO_ENTRY_MENU_ITEM_H__ #include G_BEGIN_DECLS #define IDO_TYPE_ENTRY_MENU_ITEM (ido_entry_menu_item_get_type ()) #define IDO_ENTRY_MENU_ITEM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), IDO_TYPE_ENTRY_MENU_ITEM, IdoEntryMenuItem)) #define IDO_ENTRY_MENU_ITEM_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), IDO_TYPE_ENTRY_MENU_ITEM, IdoEntryMenuItemClass)) #define IDO_IS_ENTRY_MENU_ITEM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), IDO_TYPE_ENTRY_MENU_ITEM)) #define IDO_IS_ENTRY_MENU_ITEM_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), IDO_TYPE_ENTRY_MENU_ITEM)) #define IDO_ENTRY_MENU_ITEM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), IDO_TYPE_ENTRY_MENU_ITEM, IdoEntryMenuItemClass)) typedef struct _IdoEntryMenuItem IdoEntryMenuItem; typedef struct _IdoEntryMenuItemClass IdoEntryMenuItemClass; typedef struct _IdoEntryMenuItemPrivate IdoEntryMenuItemPrivate; struct _IdoEntryMenuItem { GtkMenuItem parent_instance; IdoEntryMenuItemPrivate *priv; }; struct _IdoEntryMenuItemClass { GtkMenuItemClass parent_class; }; GType ido_entry_menu_item_get_type (void) G_GNUC_CONST; GtkWidget *ido_entry_menu_item_new (void); GtkWidget *ido_entry_menu_item_get_entry (IdoEntryMenuItem *menuitem); G_END_DECLS #endif /* __IDO_ENTRY_MENU_ITEM_H__ */ ./src/idoentrymenuitem.c0000644000004100000410000002067214320114711015600 0ustar www-datawww-data/* * Copyright 2010 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of either or both of the following licenses: * * 1) the GNU Lesser General Public License version 3, as published by the * Free Software Foundation; and/or * 2) the GNU Lesser General Public License version 2.1, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License version 3 and version 2.1 along with this program. If not, see * * * Authors: * Cody Russell */ #include #include "idoentrymenuitem.h" #include "config.h" static void ido_entry_menu_item_select (GtkMenuItem *item); static void ido_entry_menu_item_deselect (GtkMenuItem *item); static gboolean ido_entry_menu_item_button_release (GtkWidget *widget, GdkEventButton *event); static gboolean ido_entry_menu_item_key_press (GtkWidget *widget, GdkEventKey *event, gpointer data); static gboolean ido_entry_menu_item_button_press (GtkWidget *widget, GdkEventButton *event); static void ido_entry_menu_item_send_focus_change (GtkWidget *widget, gboolean in); static void entry_realized_cb (GtkWidget *widget, IdoEntryMenuItem *item); static void entry_move_focus_cb (GtkWidget *widget, GtkDirectionType direction, IdoEntryMenuItem *item); struct _IdoEntryMenuItemPrivate { GtkWidget *box; GtkWidget *entry; gboolean selected; }; G_DEFINE_TYPE (IdoEntryMenuItem, ido_entry_menu_item, GTK_TYPE_MENU_ITEM) #define IDO_ENTRY_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), IDO_TYPE_ENTRY_MENU_ITEM, IdoEntryMenuItemPrivate)) static void ido_entry_menu_item_class_init (IdoEntryMenuItemClass *klass) { GObjectClass *gobject_class; GtkWidgetClass *widget_class; GtkMenuItemClass *menu_item_class; gobject_class = G_OBJECT_CLASS (klass); widget_class = GTK_WIDGET_CLASS (klass); menu_item_class = GTK_MENU_ITEM_CLASS (klass); widget_class->button_release_event = ido_entry_menu_item_button_release; widget_class->button_press_event = ido_entry_menu_item_button_press; menu_item_class->select = ido_entry_menu_item_select; menu_item_class->deselect = ido_entry_menu_item_deselect; menu_item_class->hide_on_activate = TRUE; g_type_class_add_private (gobject_class, sizeof (IdoEntryMenuItemPrivate)); } static void ido_entry_menu_item_init (IdoEntryMenuItem *item) { IdoEntryMenuItemPrivate *priv; GtkBorder border; border.left = 4; border.right = 4; border.top = 2; border.bottom = 2; priv = item->priv = IDO_ENTRY_MENU_ITEM_GET_PRIVATE (item); priv->entry = g_object_new (gtk_entry_get_type (), "inner-border", &border, NULL); g_signal_connect (priv->entry, "realize", G_CALLBACK (entry_realized_cb), item); g_signal_connect (priv->entry, "move-focus", G_CALLBACK (entry_move_focus_cb), item); priv->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start (GTK_BOX (priv->box), priv->entry, FALSE, FALSE, 0); gtk_container_add (GTK_CONTAINER (item), priv->box); gtk_widget_show_all (priv->box); } static gboolean is_key_press_valid (IdoEntryMenuItem *item, gint key) { switch (key) { case GDK_KEY_Escape: case GDK_KEY_Up: case GDK_KEY_Down: case GDK_KEY_KP_Up: case GDK_KEY_KP_Down: return FALSE; default: return TRUE; } } static gboolean ido_entry_menu_item_key_press (GtkWidget *widget, GdkEventKey *event, gpointer data) { IdoEntryMenuItem *menuitem = (IdoEntryMenuItem *)data; if (menuitem->priv->selected && is_key_press_valid (menuitem, event->keyval)) { GtkWidget *entry = menuitem->priv->entry; gtk_widget_event (entry, ((GdkEvent *)(void*)(event))); /* We've handled the event, but if the key was GDK_KEY_Return * we still want to forward the event up to the menu shell * to ensure that the menuitem receives the activate signal. */ return event->keyval != GDK_KEY_Return; } return FALSE; } static void ido_entry_menu_item_send_focus_change (GtkWidget *widget, gboolean in) { GdkEvent *event = gdk_event_new (GDK_FOCUS_CHANGE); g_object_ref (widget); event->focus_change.type = GDK_FOCUS_CHANGE; event->focus_change.window = g_object_ref (gtk_widget_get_window (widget)); event->focus_change.in = in; gtk_widget_event (widget, event); g_object_notify (G_OBJECT (widget), "has-focus"); g_object_unref (widget); gdk_event_free (event); } static gboolean ido_entry_menu_item_button_press (GtkWidget *widget, GdkEventButton *event) { GtkWidget *entry = IDO_ENTRY_MENU_ITEM (widget)->priv->entry; if (event->button == 1) { if (gtk_widget_get_window (entry) != NULL) { gdk_window_raise (gtk_widget_get_window (entry)); } if (!gtk_widget_has_focus (entry)) { gtk_widget_grab_focus (entry); } gtk_widget_event (entry, ((GdkEvent *)(void*)(event))); return TRUE; } return FALSE; } static gboolean ido_entry_menu_item_button_release (GtkWidget *widget, GdkEventButton *event) { GtkWidget *entry = IDO_ENTRY_MENU_ITEM (widget)->priv->entry; gtk_widget_event (entry, ((GdkEvent *)(void*)(event))); return TRUE; } static void ido_entry_menu_item_select (GtkMenuItem *item) { IDO_ENTRY_MENU_ITEM (item)->priv->selected = TRUE; ido_entry_menu_item_send_focus_change (GTK_WIDGET (IDO_ENTRY_MENU_ITEM (item)->priv->entry), TRUE); } static void ido_entry_menu_item_deselect (GtkMenuItem *item) { IDO_ENTRY_MENU_ITEM (item)->priv->selected = FALSE; ido_entry_menu_item_send_focus_change (GTK_WIDGET (IDO_ENTRY_MENU_ITEM (item)->priv->entry), FALSE); } static void entry_realized_cb (GtkWidget *widget, IdoEntryMenuItem *item) { if (gtk_widget_get_window (widget) != NULL) { gdk_window_raise (gtk_widget_get_window (widget)); } g_signal_connect (gtk_widget_get_parent (GTK_WIDGET (item)), "key-press-event", G_CALLBACK (ido_entry_menu_item_key_press), item); ido_entry_menu_item_send_focus_change (widget, TRUE); } static void entry_move_focus_cb (GtkWidget *widget, GtkDirectionType direction, IdoEntryMenuItem *item) { ido_entry_menu_item_send_focus_change (GTK_WIDGET (IDO_ENTRY_MENU_ITEM (item)->priv->entry), FALSE); g_signal_emit_by_name (item, "move-focus", GTK_DIR_TAB_FORWARD); } /** * ido_entry_menu_item_new: * * Creates a new #IdoEntryMenuItem. * * Return Value: the newly created #IdoEntryMenuItem. */ GtkWidget * ido_entry_menu_item_new (void) { return g_object_new (IDO_TYPE_ENTRY_MENU_ITEM, NULL); } /** * ido_entry_menu_item_get_entry: * @menuitem: The #IdoEntryMenuItem. * * Get the #GtkEntry used in this menu item. * * Return Value: (transfer none): The #GtkEntry inside this menu item. */ GtkWidget * ido_entry_menu_item_get_entry (IdoEntryMenuItem *menuitem) { g_return_val_if_fail (IDO_IS_ENTRY_MENU_ITEM (menuitem), NULL); return menuitem->priv->entry; } ./src/idotimestampmenuitem.h0000644000004100000410000000461314320114711016444 0ustar www-datawww-data/** * Copyright 2013 Canonical Ltd. * * Authors: * Charles Kerr * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifndef __IDO_TIME_STAMP_MENU_ITEM_H__ #define __IDO_TIME_STAMP_MENU_ITEM_H__ #include #include "idobasicmenuitem.h" G_BEGIN_DECLS #define IDO_TYPE_TIME_STAMP_MENU_ITEM (ido_time_stamp_menu_item_get_type ()) #define IDO_TIME_STAMP_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IDO_TYPE_TIME_STAMP_MENU_ITEM, IdoTimeStampMenuItem)) #define IDO_IS_TIME_STAMP_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IDO_TYPE_TIME_STAMP_MENU_ITEM)) typedef struct _IdoTimeStampMenuItem IdoTimeStampMenuItem; typedef struct _IdoTimeStampMenuItemClass IdoTimeStampMenuItemClass; typedef struct _IdoTimeStampMenuItemPrivate IdoTimeStampMenuItemPrivate; struct _IdoTimeStampMenuItemClass { IdoBasicMenuItemClass parent_class; }; /** * A menuitem that contains a left-aligned optional icon and label * and a right-aligned secondary label showing the specified time * in the specified format. * * Used by IdoLocationMenuItem, IdoAppointmentMenuItem, and IdoAlarmMenuItem. */ struct _IdoTimeStampMenuItem { /*< private >*/ IdoBasicMenuItem parent; IdoTimeStampMenuItemPrivate * priv; }; GType ido_time_stamp_menu_item_get_type (void) G_GNUC_CONST; GtkWidget * ido_time_stamp_menu_item_new (void); void ido_time_stamp_menu_item_set_date_time (IdoTimeStampMenuItem * menuitem, GDateTime * date_time); void ido_time_stamp_menu_item_set_format (IdoTimeStampMenuItem * menuitem, const char * strftime_fmt); const char * ido_time_stamp_menu_item_get_format (IdoTimeStampMenuItem * menuitem); G_END_DECLS #endif ./src/idomediaplayermenuitem.h0000644000004100000410000000313414320114711016732 0ustar www-datawww-data/* * Copyright 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * * Authors: * Conor Curran * Mirco Müller * Lars Uebernickel */ #ifndef __IDO_MEDIA_PLAYER_MENU_ITEM_H__ #define __IDO_MEDIA_PLAYER_MENU_ITEM_H__ #include G_BEGIN_DECLS #define IDO_TYPE_MEDIA_PLAYER_MENU_ITEM (ido_media_player_menu_item_get_type ()) #define IDO_MEDIA_PLAYER_MENU_ITEM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), IDO_TYPE_MEDIA_PLAYER_MENU_ITEM, IdoMediaPlayerMenuItem)) #define IDO_IS_MEDIA_PLAYER_MENU_ITEM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), IDO_TYPE_MEDIA_PLAYER_MENU_ITEM)) typedef struct _IdoMediaPlayerMenuItem IdoMediaPlayerMenuItem; GType ido_media_player_menu_item_get_type (void); GtkMenuItem * ido_media_player_menu_item_new_from_model (GMenuItem *menuitem, GActionGroup *actions); G_END_DECLS #endif ./src/idoscalemenuitem.c0000644000004100000410000010724114320114711015524 0ustar www-datawww-data/* * Copyright 2010 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of either or both of the following licenses: * * 1) the GNU Lesser General Public License version 3, as published by the * Free Software Foundation; and/or * 2) the GNU Lesser General Public License version 2.1, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License version 3 and version 2.1 along with this program. If not, see * * * Authors: * Cody Russell */ #include "config.h" #include #include "idorange.h" #include "idoscalemenuitem.h" #include "idotypebuiltins.h" #include "idoactionhelper.h" static void ido_scale_menu_item_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void ido_scale_menu_item_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static gboolean ido_scale_menu_item_parent_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data); static void ido_scale_menu_item_select (GtkMenuItem *item); static void ido_scale_menu_item_deselect (GtkMenuItem *item); static gboolean ido_scale_menu_item_button_press_event (GtkWidget *menuitem, GdkEventButton *event); static gboolean ido_scale_menu_item_button_release_event (GtkWidget *menuitem, GdkEventButton *event); static gboolean ido_scale_menu_item_motion_notify_event (GtkWidget *menuitem, GdkEventMotion *event); static void ido_scale_menu_item_primary_image_notify (GtkImage *image, GParamSpec *pspec, IdoScaleMenuItem *item); static void ido_scale_menu_item_secondary_image_notify (GtkImage *image, GParamSpec *pspec, IdoScaleMenuItem *item); static void ido_scale_menu_item_parent_set (GtkWidget *item, GtkWidget *previous_parent); static void update_packing (IdoScaleMenuItem *self, IdoScaleMenuItemStyle style); static void default_primary_clicked_handler (IdoScaleMenuItem *self); static void default_secondary_clicked_handler (IdoScaleMenuItem *self); struct _IdoScaleMenuItemPrivate { GtkWidget *scale; GtkAdjustment *adjustment; GtkWidget *primary_image; GtkWidget *secondary_image; GtkWidget *primary_label; GtkWidget *secondary_label; GtkWidget *hbox; gboolean reverse_scroll; gboolean grabbed; IdoScaleMenuItemStyle style; IdoRangeStyle range_style; gboolean ignore_value_changed; gboolean has_focus; }; enum { SLIDER_GRABBED, SLIDER_RELEASED, PRIMARY_CLICKED, SECONDARY_CLICKED, VALUE_CHANGED, LAST_SIGNAL }; enum { PROP_0, PROP_ADJUSTMENT, PROP_REVERSE_SCROLL_EVENTS, PROP_STYLE, PROP_RANGE_STYLE }; static guint signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE (IdoScaleMenuItem, ido_scale_menu_item, GTK_TYPE_MENU_ITEM) #define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), IDO_TYPE_SCALE_MENU_ITEM, IdoScaleMenuItemPrivate)) static gboolean ido_scale_menu_item_scroll_event (GtkWidget *menuitem, GdkEventScroll *event) { IdoScaleMenuItemPrivate *priv = GET_PRIVATE (menuitem); GtkWidget *scale = priv->scale; if (priv->reverse_scroll) { switch (event->direction) { case GDK_SCROLL_UP: event->direction = GDK_SCROLL_DOWN; break; case GDK_SCROLL_DOWN: event->direction = GDK_SCROLL_UP; break; default: break; } } gtk_widget_event (scale, ((GdkEvent *)(void*)(event))); return TRUE; } static void ido_scale_menu_item_scale_value_changed (GtkRange *range, gpointer user_data) { IdoScaleMenuItem *self = user_data; IdoScaleMenuItemPrivate *priv = GET_PRIVATE (self); /* The signal is not sent when it was set through * ido_scale_menu_item_set_value(). */ if (!priv->ignore_value_changed) g_signal_emit (self, signals[VALUE_CHANGED], 0, gtk_range_get_value (range)); } static void ido_scale_menu_item_constructed (GObject *object) { IdoScaleMenuItem *self = IDO_SCALE_MENU_ITEM (object); IdoScaleMenuItemPrivate *priv = GET_PRIVATE (self); GObject *adj = G_OBJECT (gtk_adjustment_new (0.0, 0.0, 100.0, 1.0, 10.0, 0.0)); IdoRangeStyle range_style; GtkWidget *hbox; priv->adjustment = NULL; g_object_get (self, "range-style", &range_style, NULL); priv->scale = ido_range_new (adj, range_style); g_signal_connect (priv->scale, "value-changed", G_CALLBACK (ido_scale_menu_item_scale_value_changed), self); g_object_ref (priv->scale); gtk_scale_set_draw_value (GTK_SCALE (priv->scale), FALSE); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); priv->primary_image = gtk_image_new (); g_signal_connect (priv->primary_image, "notify", G_CALLBACK (ido_scale_menu_item_primary_image_notify), self); priv->secondary_image = gtk_image_new (); g_signal_connect (priv->secondary_image, "notify", G_CALLBACK (ido_scale_menu_item_secondary_image_notify), self); priv->primary_label = gtk_label_new (""); priv->secondary_label = gtk_label_new (""); priv->hbox = hbox; update_packing (self, priv->style); gtk_container_add (GTK_CONTAINER (self), hbox); gtk_widget_add_events (GTK_WIDGET(self), GDK_SCROLL_MASK); } static void ido_scale_menu_item_class_init (IdoScaleMenuItemClass *item_class) { GObjectClass *gobject_class = G_OBJECT_CLASS (item_class); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (item_class); GtkMenuItemClass *menuitem_class = GTK_MENU_ITEM_CLASS (item_class); item_class->primary_clicked = default_primary_clicked_handler; item_class->secondary_clicked = default_secondary_clicked_handler; menuitem_class->select = ido_scale_menu_item_select; menuitem_class->deselect = ido_scale_menu_item_deselect; widget_class->button_press_event = ido_scale_menu_item_button_press_event; widget_class->button_release_event = ido_scale_menu_item_button_release_event; widget_class->motion_notify_event = ido_scale_menu_item_motion_notify_event; widget_class->scroll_event = ido_scale_menu_item_scroll_event; widget_class->parent_set = ido_scale_menu_item_parent_set; gobject_class->constructed = ido_scale_menu_item_constructed; gobject_class->set_property = ido_scale_menu_item_set_property; gobject_class->get_property = ido_scale_menu_item_get_property; g_object_class_install_property (gobject_class, PROP_STYLE, g_param_spec_enum ("accessory-style", "Style of primary/secondary widgets", "The style of the primary/secondary widgets", IDO_TYPE_SCALE_MENU_ITEM_STYLE, IDO_SCALE_MENU_ITEM_STYLE_NONE, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_RANGE_STYLE, g_param_spec_enum ("range-style", "Range style", "Style of the range", IDO_TYPE_RANGE_STYLE, IDO_RANGE_STYLE_DEFAULT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (gobject_class, PROP_ADJUSTMENT, g_param_spec_object ("adjustment", "Adjustment", "The adjustment containing the scale value", GTK_TYPE_ADJUSTMENT, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_REVERSE_SCROLL_EVENTS, g_param_spec_boolean ("reverse-scroll-events", "Reverse scroll events", "Reverses how up/down scroll events are interpreted", TRUE, G_PARAM_READWRITE)); /** * IdoScaleMenuItem::slider-grabbed: * @menuitem: The #IdoScaleMenuItem emitting the signal. * * The ::slider-grabbed signal is emitted when the pointer selects the slider. */ signals[SLIDER_GRABBED] = g_signal_new ("slider-grabbed", G_OBJECT_CLASS_TYPE (gobject_class), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * IdoScaleMenuItem::slider-released: * @menuitem: The #IdoScaleMenuItem emitting the signal. * * The ::slider-released signal is emitted when the pointer releases the slider. */ signals[SLIDER_RELEASED] = g_signal_new ("slider-released", G_OBJECT_CLASS_TYPE (gobject_class), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * IdoScaleMenuItem::primary-clicked: * @menuitem: The #IdoScaleMenuItem emitting the signal. * * The ::primary-clicked signal is emitted when the pointer clicks the primary label. */ signals[PRIMARY_CLICKED] = g_signal_new ("primary-clicked", G_TYPE_FROM_CLASS (item_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, G_STRUCT_OFFSET (IdoScaleMenuItemClass, primary_clicked), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, /* return type */ 0 /* n_params */); /** * IdoScaleMenuItem::secondary-clicked: * @menuitem: The #IdoScaleMenuItem emitting the signal. * * The ::secondary-clicked signal is emitted when the pointer clicks the secondary label. */ signals[SECONDARY_CLICKED] = g_signal_new ("secondary-clicked", G_TYPE_FROM_CLASS (item_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, G_STRUCT_OFFSET (IdoScaleMenuItemClass, secondary_clicked), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, /* return type */ 0 /* n_params */); /** * IdoScaleMenuItem::value-changed: * @menuitem: the #IdoScaleMenuItem for which the value changed * @value: the new value * * Emitted whenever the value of the contained scale changes because * of user input. */ signals[VALUE_CHANGED] = g_signal_new ("value-changed", IDO_TYPE_SCALE_MENU_ITEM, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__DOUBLE, G_TYPE_NONE, 1, G_TYPE_DOUBLE); g_type_class_add_private (item_class, sizeof (IdoScaleMenuItemPrivate)); } static void update_packing (IdoScaleMenuItem *self, IdoScaleMenuItemStyle style) { IdoScaleMenuItemPrivate *priv = GET_PRIVATE (self); GtkBox * box = GTK_BOX (priv->hbox); GtkContainer *container = GTK_CONTAINER (priv->hbox); /* remove the old layout */ GList * children = gtk_container_get_children (container); GList * l; for (l=children; l!=NULL; l=l->next) gtk_container_remove (container, l->data); g_list_free (children); /* add the new layout */ switch (style) { case IDO_SCALE_MENU_ITEM_STYLE_IMAGE: gtk_box_pack_start (box, priv->primary_image, FALSE, FALSE, 0); gtk_box_pack_start (box, priv->scale, TRUE, TRUE, 0); gtk_box_pack_start (box, priv->secondary_image, FALSE, FALSE, 0); break; case IDO_SCALE_MENU_ITEM_STYLE_LABEL: gtk_box_pack_start (box, priv->primary_label, FALSE, FALSE, 0); gtk_box_pack_start (box, priv->scale, TRUE, TRUE, 0); gtk_box_pack_start (box, priv->secondary_label, FALSE, FALSE, 0); break; default: gtk_box_pack_start (box, priv->scale, TRUE, TRUE, 0); break; } gtk_widget_show_all (priv->hbox); } static void ido_scale_menu_item_init (IdoScaleMenuItem *self) { IdoScaleMenuItemPrivate *priv = GET_PRIVATE (self); priv->reverse_scroll = TRUE; gtk_widget_set_size_request (GTK_WIDGET (self), 200, -1); } static void ido_scale_menu_item_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { IdoScaleMenuItem *menu_item = IDO_SCALE_MENU_ITEM (object); IdoScaleMenuItemPrivate *priv = GET_PRIVATE (menu_item); switch (prop_id) { case PROP_ADJUSTMENT: gtk_range_set_adjustment (GTK_RANGE (priv->scale), g_value_get_object (value)); break; case PROP_REVERSE_SCROLL_EVENTS: priv->reverse_scroll = g_value_get_boolean (value); break; case PROP_STYLE: ido_scale_menu_item_set_style (menu_item, g_value_get_enum (value)); break; case PROP_RANGE_STYLE: priv->range_style = g_value_get_enum (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void ido_scale_menu_item_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { IdoScaleMenuItem *menu_item = IDO_SCALE_MENU_ITEM (object); IdoScaleMenuItemPrivate *priv = GET_PRIVATE (menu_item); GtkAdjustment *adjustment; switch (prop_id) { case PROP_ADJUSTMENT: adjustment = gtk_range_get_adjustment (GTK_RANGE (priv->scale)); g_value_set_object (value, adjustment); break; case PROP_REVERSE_SCROLL_EVENTS: g_value_set_boolean (value, priv->reverse_scroll); break; case PROP_RANGE_STYLE: g_value_set_enum (value, priv->range_style); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static gboolean ido_scale_menu_item_parent_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data) { IdoScaleMenuItemPrivate *priv = GET_PRIVATE (user_data); /* only listen to events when the playback menu item is selected */ if (!priv->has_focus) return FALSE; switch (event->keyval) { case GDK_KEY_Left: case GDK_KEY_minus: case GDK_KEY_KP_Subtract: GTK_RANGE_GET_CLASS (priv->scale)->move_slider (GTK_RANGE (priv->scale), GTK_SCROLL_STEP_LEFT); return TRUE; case GDK_KEY_Right: case GDK_KEY_plus: case GDK_KEY_KP_Add: GTK_RANGE_GET_CLASS (priv->scale)->move_slider (GTK_RANGE (priv->scale), GTK_SCROLL_STEP_RIGHT); return TRUE; } return FALSE; } static void ido_scale_menu_item_select (GtkMenuItem *item) { IdoScaleMenuItemPrivate *priv = GET_PRIVATE (item); priv->has_focus = TRUE; gtk_widget_set_state_flags (priv->scale, GTK_STATE_FLAG_FOCUSED, FALSE); GTK_MENU_ITEM_CLASS (ido_scale_menu_item_parent_class)->select (item); } static void ido_scale_menu_item_deselect (GtkMenuItem *item) { IdoScaleMenuItemPrivate *priv = GET_PRIVATE (item); priv->has_focus = FALSE; gtk_widget_unset_state_flags (priv->scale, GTK_STATE_FLAG_FOCUSED); GTK_MENU_ITEM_CLASS (ido_scale_menu_item_parent_class)->deselect (item); } static gboolean ido_scale_menu_item_button_press_event (GtkWidget *menuitem, GdkEventButton *event) { IdoScaleMenuItemPrivate *priv = GET_PRIVATE (menuitem); GtkAllocation alloc; gint x, y; gtk_widget_get_allocation (priv->scale, &alloc); gtk_widget_translate_coordinates (menuitem, priv->scale, event->x, event->y, &x, &y); if (x > 0 && x < alloc.width && y > 0 && y < alloc.height) gtk_widget_event (priv->scale, (GdkEvent *) event); if (!priv->grabbed) { priv->grabbed = TRUE; g_signal_emit (menuitem, signals[SLIDER_GRABBED], 0); } return TRUE; } static gboolean ido_scale_menu_item_button_release_event (GtkWidget *menuitem, GdkEventButton *event) { IdoScaleMenuItem *item = IDO_SCALE_MENU_ITEM (menuitem); IdoScaleMenuItemPrivate *priv = GET_PRIVATE (menuitem); GtkWidget *scale = priv->scale; GtkAllocation alloc; gint x, y; gtk_widget_get_allocation (priv->scale, &alloc); gtk_widget_translate_coordinates (menuitem, priv->scale, event->x, event->y, &x, &y); /* if user clicked to the left of the scale... */ if (x < 0) { if (gtk_widget_get_direction (menuitem) == GTK_TEXT_DIR_LTR) { ido_scale_menu_item_primary_clicked (item); } else { ido_scale_menu_item_secondary_clicked (item); } } /* if user clicked to the right of the scale... */ else if (x > alloc.width) { if (gtk_widget_get_direction (menuitem) == GTK_TEXT_DIR_LTR) { ido_scale_menu_item_secondary_clicked (item); } else { ido_scale_menu_item_primary_clicked (item); } } /* user clicked on the scale... */ else if (x > 0 && x < alloc.width && y > 0 && y < alloc.height) { gtk_widget_event (scale, (GdkEvent*) event); } if (priv->grabbed) { priv->grabbed = FALSE; g_signal_emit (menuitem, signals[SLIDER_RELEASED], 0); } return TRUE; } static gboolean ido_scale_menu_item_motion_notify_event (GtkWidget *menuitem, GdkEventMotion *event) { IdoScaleMenuItemPrivate *priv = GET_PRIVATE (menuitem); GtkAllocation alloc; gint x, y; gtk_widget_get_allocation (priv->scale, &alloc); gtk_widget_translate_coordinates (menuitem, priv->scale, event->x, event->y, &x, &y); /* don't translate coordinates when the scale has the "grab" - * GtkRange expects coords relative to its event window in that case */ if (!priv->grabbed) { event->x = x; event->y = y; } if (priv->grabbed || (x > 0 && x < alloc.width && y > 0 && y < alloc.height)) gtk_widget_event (priv->scale, (GdkEvent *) event); return TRUE; } static void menu_hidden (GtkWidget *menu, IdoScaleMenuItem *scale) { IdoScaleMenuItemPrivate *priv = GET_PRIVATE (scale); if (priv->grabbed) { priv->grabbed = FALSE; g_signal_emit (scale, signals[SLIDER_RELEASED], 0); } } static void ido_scale_menu_item_parent_set (GtkWidget *item, GtkWidget *previous_parent) { GtkWidget *parent; if (previous_parent) { g_signal_handlers_disconnect_by_func (previous_parent, menu_hidden, item); g_signal_handlers_disconnect_by_func (previous_parent, ido_scale_menu_item_parent_key_press_event, item); } parent = gtk_widget_get_parent (item); if (parent) { g_signal_connect (parent, "hide", G_CALLBACK (menu_hidden), item); /* Menus don't pass key events to their children. This works around * that by listening to key events on the parent widget. */ g_signal_connect (parent, "key-press-event", G_CALLBACK (ido_scale_menu_item_parent_key_press_event), item); } } static void ido_scale_menu_item_primary_image_notify (GtkImage *image, GParamSpec *pspec, IdoScaleMenuItem *item) { if (gtk_image_get_storage_type (image) == GTK_IMAGE_EMPTY) gtk_widget_hide (GTK_WIDGET (image)); else gtk_widget_show (GTK_WIDGET (image)); } static void ido_scale_menu_item_secondary_image_notify (GtkImage *image, GParamSpec *pspec, IdoScaleMenuItem *item) { if (gtk_image_get_storage_type (image) == GTK_IMAGE_EMPTY) gtk_widget_hide (GTK_WIDGET (image)); else gtk_widget_show (GTK_WIDGET (image)); } /** * ido_scale_menu_item_new: * @label: the text of the new menu item. * @size: The size style of the range. * @adjustment: A #GtkAdjustment describing the slider value. * * Creates a new #IdoScaleMenuItem with an empty label. * * Return Value: a new #IdoScaleMenuItem. **/ GtkWidget* ido_scale_menu_item_new (const gchar *label, IdoRangeStyle range_style, GtkAdjustment *adjustment) { return g_object_new (IDO_TYPE_SCALE_MENU_ITEM, "adjustment", adjustment, "range-style", range_style, NULL); } /** * ido_scale_menu_item_new_with_label: * @label: the text of the menu item. * @size: The size style of the range. * @min: The minimum value of the slider. * @max: The maximum value of the slider. * @step: The step increment of the slider. * * Creates a new #IdoScaleMenuItem containing a label. * * Return Value: a new #IdoScaleMenuItem. **/ GtkWidget* ido_scale_menu_item_new_with_range (const gchar *label, IdoRangeStyle range_style, gdouble value, gdouble min, gdouble max, gdouble step) { GObject *adjustment = G_OBJECT (gtk_adjustment_new (value, min, max, step, 10 * step, 0)); return GTK_WIDGET (g_object_new (IDO_TYPE_SCALE_MENU_ITEM, "label", label, "range-style", range_style, "adjustment", adjustment, NULL)); } /** * ido_scale_menu_item_get_scale: * @menuitem: The #IdoScaleMenuItem * * Retrieves the scale widget. * * Return Value: (transfer none): The #IdoRange in this item **/ GtkWidget* ido_scale_menu_item_get_scale (IdoScaleMenuItem *menuitem) { IdoScaleMenuItemPrivate *priv; g_return_val_if_fail (IDO_IS_SCALE_MENU_ITEM (menuitem), NULL); priv = GET_PRIVATE (menuitem); return priv->scale; } /** * ido_scale_menu_item_get_style: * @menuitem: The #IdoScaleMenuItem * * Retrieves the type of widgets being used for the primary and * secondary widget slots. This could be images, labels, or nothing. * * Return Value: A #IdoScaleMenuItemStyle enum describing the style. **/ IdoScaleMenuItemStyle ido_scale_menu_item_get_style (IdoScaleMenuItem *menuitem) { IdoScaleMenuItemPrivate *priv; g_return_val_if_fail (IDO_IS_SCALE_MENU_ITEM (menuitem), IDO_SCALE_MENU_ITEM_STYLE_NONE); priv = GET_PRIVATE (menuitem); return priv->style; } /** * ido_scale_menu_item_set_style: * @menuitem: The #IdoScaleMenuItem * @style: Set the style use for the primary and secondary widget slots. * * Sets the type of widgets being used for the primary and * secondary widget slots. This could be images, labels, or nothing. **/ void ido_scale_menu_item_set_style (IdoScaleMenuItem *menuitem, IdoScaleMenuItemStyle style) { IdoScaleMenuItemPrivate *priv; g_return_if_fail (IDO_IS_SCALE_MENU_ITEM (menuitem)); priv = GET_PRIVATE (menuitem); priv->style = style; update_packing (menuitem, style); } /** * ido_scale_menu_item_get_primary_image: * @menuitem: The #IdoScaleMenuItem * * Retrieves a pointer to the image widget used in the primary slot. * Whether this is visible depends upon the return value from * ido_scale_menu_item_get_style(). * * Return Value: (transfer none): A #GtkWidget pointer for the primary image. **/ GtkWidget * ido_scale_menu_item_get_primary_image (IdoScaleMenuItem *menuitem) { IdoScaleMenuItemPrivate *priv; g_return_val_if_fail (IDO_IS_SCALE_MENU_ITEM (menuitem), NULL); priv = GET_PRIVATE (menuitem); return priv->primary_image; } /** * ido_scale_menu_item_get_secondary_image: * @menuitem: The #IdoScaleMenuItem * * Retrieves a pointer to the image widget used in the secondary slot. * Whether this is visible depends upon the return value from * ido_scale_menu_item_get_style(). * * Return Value: (transfer none): A #GtkWidget pointer for the secondary image. **/ GtkWidget * ido_scale_menu_item_get_secondary_image (IdoScaleMenuItem *menuitem) { IdoScaleMenuItemPrivate *priv; g_return_val_if_fail (IDO_IS_SCALE_MENU_ITEM (menuitem), NULL); priv = GET_PRIVATE (menuitem); return priv->secondary_image; } /** * ido_scale_menu_item_set_icons: * @item: a #IdoScaleMenuItem * @primary-icon: (allow-none): the primary icon, or %NULL * @secondary-icon: (allow-none): the secondary icon, %NULL * * Sets the icons of @item to @primary_icon and @secondary_icon. * Pass %NULL for either of them to unset the icon. */ static void ido_scale_menu_item_set_icons (IdoScaleMenuItem *item, GIcon *primary_icon, GIcon *secondary_icon) { GtkWidget *primary; GtkWidget *secondary; primary = ido_scale_menu_item_get_primary_image (item); secondary = ido_scale_menu_item_get_secondary_image (item); if (primary_icon) gtk_image_set_from_gicon (GTK_IMAGE (primary), primary_icon, GTK_ICON_SIZE_MENU); else gtk_image_clear (GTK_IMAGE (primary)); if (secondary_icon) gtk_image_set_from_gicon (GTK_IMAGE (secondary), secondary_icon, GTK_ICON_SIZE_MENU); else gtk_image_clear (GTK_IMAGE (secondary)); } /** * ido_scale_menu_item_get_primary_label: * @menuitem: The #IdoScaleMenuItem * * Retrieves a string of the text for the primary label widget. * Whether this is visible depends upon the return value from * ido_scale_menu_item_get_style(). * * Return Value: The label text. **/ const gchar* ido_scale_menu_item_get_primary_label (IdoScaleMenuItem *menuitem) { IdoScaleMenuItemPrivate *priv; g_return_val_if_fail (IDO_IS_SCALE_MENU_ITEM (menuitem), NULL); priv = GET_PRIVATE (menuitem); return gtk_label_get_text (GTK_LABEL (priv->primary_label)); } /** * ido_scale_menu_item_get_secondary_label: * @menuitem: The #IdoScaleMenuItem * * Retrieves a string of the text for the secondary label widget. * Whether this is visible depends upon the return value from * ido_scale_menu_item_get_style(). * * Return Value: The label text. **/ const gchar* ido_scale_menu_item_get_secondary_label (IdoScaleMenuItem *menuitem) { IdoScaleMenuItemPrivate *priv; g_return_val_if_fail (IDO_IS_SCALE_MENU_ITEM (menuitem), NULL); priv = GET_PRIVATE (menuitem); return gtk_label_get_text (GTK_LABEL (priv->secondary_label)); } /** * ido_scale_menu_item_set_primary_label: * @menuitem: The #IdoScaleMenuItem * @label: The label text * * Sets the text for the label widget in the primary slot. This * widget will only be visibile if the return value of * ido_scale_menu_item_get_style() is set to %IDO_SCALE_MENU_ITEM_STYLE_LABEL. **/ void ido_scale_menu_item_set_primary_label (IdoScaleMenuItem *menuitem, const gchar *label) { IdoScaleMenuItemPrivate *priv; g_return_if_fail (IDO_IS_SCALE_MENU_ITEM (menuitem)); priv = GET_PRIVATE (menuitem); if (priv->primary_label) { gtk_label_set_text (GTK_LABEL (priv->primary_label), label); } } /** * ido_scale_menu_item_set_secondary_label: * @menuitem: The #IdoScaleMenuItem * @label: The label text * * Sets the text for the label widget in the secondary slot. This * widget will only be visibile if the return value of * ido_scale_menu_item_get_style() is set to %IDO_SCALE_MENU_ITEM_STYLE_LABEL. **/ void ido_scale_menu_item_set_secondary_label (IdoScaleMenuItem *menuitem, const gchar *label) { IdoScaleMenuItemPrivate *priv; g_return_if_fail (IDO_IS_SCALE_MENU_ITEM (menuitem)); priv = GET_PRIVATE (menuitem); if (priv->secondary_label) { gtk_label_set_text (GTK_LABEL (priv->secondary_label), label); } } /** * ido_scale_menu_item_primary_clicked: * @menuitem: the #IdoScaleMenuItem * * Emits the "primary-clicked" signal. * * The default handler for this signal lowers the scale's * adjustment to its lower bound. */ void ido_scale_menu_item_primary_clicked (IdoScaleMenuItem * menuitem) { g_signal_emit (menuitem, signals[PRIMARY_CLICKED], 0); } static void default_primary_clicked_handler (IdoScaleMenuItem * item) { g_debug ("%s: setting scale to lower bound", G_STRFUNC); IdoScaleMenuItemPrivate * priv = GET_PRIVATE (item); GtkAdjustment *adj = gtk_range_get_adjustment (GTK_RANGE (priv->scale)); gtk_adjustment_set_value (adj, gtk_adjustment_get_lower (adj)); } /** * ido_scale_menu_item_secondary_clicked: * @menuitem: the #IdoScaleMenuItem * * Emits the "secondary-clicked" signal. * * The default handler for this signal raises the scale's * adjustment to its upper bound. */ void ido_scale_menu_item_secondary_clicked (IdoScaleMenuItem * menuitem) { g_signal_emit (menuitem, signals[SECONDARY_CLICKED], 0); } static void default_secondary_clicked_handler (IdoScaleMenuItem * item) { g_debug ("%s: setting scale to upper bound", G_STRFUNC); IdoScaleMenuItemPrivate * priv = GET_PRIVATE (item); GtkAdjustment *adj = gtk_range_get_adjustment (GTK_RANGE (priv->scale)); gtk_adjustment_set_value (adj, gtk_adjustment_get_upper (adj)); } /* ido_scale_menu_item_set_value: * * Sets the value of the scale inside @item to @value, without emitting * "value-changed". */ static void ido_scale_menu_item_set_value (IdoScaleMenuItem *item, gdouble value) { IdoScaleMenuItemPrivate *priv = GET_PRIVATE (item); /* set ignore_value_changed to signify to the scale menu item that it * should not emit its own value-changed signal, as that should only * be emitted when the value is changed by the user. */ priv->ignore_value_changed = TRUE; gtk_range_set_value (GTK_RANGE (priv->scale), value); priv->ignore_value_changed = FALSE; } /** * ido_scale_menu_item_state_changed: * * Updates a IdoScaleMenuItem from @state. State must be a double which * contains the current value of the slider. */ static void ido_scale_menu_item_state_changed (IdoActionHelper *helper, GVariant *state, gpointer user_data) { GtkWidget *menuitem; menuitem = ido_action_helper_get_widget (helper); ido_scale_menu_item_set_value (IDO_SCALE_MENU_ITEM (menuitem), g_variant_get_double (state)); } static void ido_scale_menu_item_value_changed (GtkScale *scale, gdouble value, gpointer user_data) { IdoActionHelper *helper = user_data; ido_action_helper_change_action_state (helper, g_variant_new_double (value)); } static GIcon * menu_item_get_icon (GMenuItem *menuitem, const gchar *attribute) { GVariant *value; value = g_menu_item_get_attribute_value (menuitem, attribute, NULL); return value ? g_icon_deserialize (value) : NULL; } /** * ido_scale_menu_item_new_from_model: * * Creates a new #IdoScaleMenuItem. If @menuitem contains an action, it * will be bound to that action in @actions. * * Returns: (transfer full): a new #IdoScaleMenuItem */ GtkMenuItem * ido_scale_menu_item_new_from_model (GMenuItem *menuitem, GActionGroup *actions) { GtkWidget *item; gchar *action; gdouble min = 0.0; gdouble max = 100.0; gdouble step = 1.0; GIcon *min_icon; GIcon *max_icon; g_menu_item_get_attribute (menuitem, "min-value", "d", &min); g_menu_item_get_attribute (menuitem, "max-value", "d", &max); g_menu_item_get_attribute (menuitem, "step", "d", &step); item = ido_scale_menu_item_new_with_range ("Volume", IDO_RANGE_STYLE_DEFAULT, 0.0, min, max, step); ido_scale_menu_item_set_style (IDO_SCALE_MENU_ITEM (item), IDO_SCALE_MENU_ITEM_STYLE_IMAGE); if (g_menu_item_get_attribute (menuitem, "action", "s", &action)) { IdoActionHelper *helper; helper = ido_action_helper_new (item, actions, action, NULL); g_signal_connect (helper, "action-state-changed", G_CALLBACK (ido_scale_menu_item_state_changed), NULL); g_signal_connect (item, "value-changed", G_CALLBACK (ido_scale_menu_item_value_changed), helper); g_signal_connect_swapped (item, "destroy", G_CALLBACK (g_object_unref), helper); g_free (action); } min_icon = menu_item_get_icon (menuitem, "min-icon"); max_icon = menu_item_get_icon (menuitem, "max-icon"); ido_scale_menu_item_set_icons (IDO_SCALE_MENU_ITEM (item), min_icon, max_icon); if (min_icon) g_object_unref (min_icon); if (max_icon) g_object_unref (max_icon); return GTK_MENU_ITEM (item); } #define __IDO_SCALE_MENU_ITEM_C__ ./src/libido.h0000644000004100000410000000224214320114711013437 0ustar www-datawww-data/* * Copyright 2010 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of either or both of the following licenses: * * 1) the GNU Lesser General Public License version 3, as published by the * Free Software Foundation; and/or * 2) the GNU Lesser General Public License version 2.1, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License version 3 and version 2.1 along with this program. If not, see * * * Authors: * Cody Russell */ #ifndef __IDO__ #define __IDO__ #include #include #include #include void ido_init (void); #endif /* __IDO__ */ ./src/idodetaillabel.h0000644000004100000410000000425614320114711015142 0ustar www-datawww-data/* * Copyright 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * * Authors: * Lars Uebernickel */ #ifndef __IDO_DETAIL_LABEL_H__ #define __IDO_DETAIL_LABEL_H__ #include #define IDO_TYPE_DETAIL_LABEL (ido_detail_label_get_type()) #define IDO_DETAIL_LABEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IDO_TYPE_DETAIL_LABEL, IdoDetailLabel)) #define IDO_DETAIL_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IDO_TYPE_DETAIL_LABEL, IdoDetailLabelClass)) #define IDO_IS_DETAIL_LABEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IDO_TYPE_DETAIL_LABEL)) #define IDO_IS_DETAIL_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IDO_TYPE_DETAIL_LABEL)) #define IDO_DETAIL_LABEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IDO_TYPE_DETAIL_LABEL, IdoDetailLabelClass)) typedef struct _IdoDetailLabel IdoDetailLabel; typedef struct _IdoDetailLabelClass IdoDetailLabelClass; typedef struct _IdoDetailLabelPrivate IdoDetailLabelPrivate; struct _IdoDetailLabel { GtkWidget parent; IdoDetailLabelPrivate *priv; }; struct _IdoDetailLabelClass { GtkWidgetClass parent_class; }; GType ido_detail_label_get_type (void) G_GNUC_CONST; GtkWidget * ido_detail_label_new (const gchar *str); const gchar * ido_detail_label_get_text (IdoDetailLabel *label); void ido_detail_label_set_text (IdoDetailLabel *label, const gchar *text); void ido_detail_label_set_count (IdoDetailLabel *label, gint count); #endif ./src/idomessagedialog.h0000644000004100000410000000611214320114711015475 0ustar www-datawww-data/* * Copyright (C) 2010 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of either or both of the following licenses: * * 1) the GNU Lesser General Public License version 3, as published by the * Free Software Foundation; and/or * 2) the GNU Lesser General Public License version 2.1, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License version 3 and version 2.1 along with this program. If not, see * * * Authors: * Cody Russell * * Design and specification: * Matthew Paul Thomas */ #ifndef __IDO_MESSAGE_DIALOG_H__ #define __IDO_MESSAGE_DIALOG_H__ #include #define IDO_TYPE_MESSAGE_DIALOG (ido_message_dialog_get_type ()) #define IDO_MESSAGE_DIALOG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), IDO_TYPE_MESSAGE_DIALOG, IdoMessageDialog)) #define IDO_MESSAGE_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), IDO_TYPE_MESSAGE_DIALOG, IdoMessageDialogClass)) #define IDO_IS_MESSAGE_DIALOG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), IDO_TYPE_MESSAGE_DIALOG)) #define IDO_IS_MESSAGE_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), IDO_TYPE_MESSAGE_DIALOG)) #define IDO_MESSAGE_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), IDO_TYPE_MESSAGE_DIALOG, IdoMessageDialogClass)) typedef struct _IdoMessageDialog IdoMessageDialog; typedef struct _IdoMessageDialogClass IdoMessageDialogClass; struct _IdoMessageDialog { GtkMessageDialog parent_instance; }; struct _IdoMessageDialogClass { GtkMessageDialogClass parent_class; /* Padding for future expansion */ void (*_ido_reserved1) (void); void (*_ido_reserved2) (void); void (*_ido_reserved3) (void); void (*_ido_reserved4) (void); }; GType ido_message_dialog_get_type (void) G_GNUC_CONST; GtkWidget* ido_message_dialog_new (GtkWindow *parent, GtkDialogFlags flags, GtkMessageType type, GtkButtonsType buttons, const gchar *message_format, ...) G_GNUC_PRINTF (5, 6); GtkWidget* ido_message_dialog_new_with_markup (GtkWindow *parent, GtkDialogFlags flags, GtkMessageType type, GtkButtonsType buttons, const gchar *message_format, ...) G_GNUC_PRINTF (5, 6); G_END_DECLS #endif /* __IDO_MESSAGE_DIALOG_H__ */ ./src/idolocationmenuitem.h0000644000004100000410000000446014320114711016251 0ustar www-datawww-data/** * Copyright 2013 Canonical Ltd. * * Authors: * Charles Kerr * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifndef __IDO_LOCATION_MENU_ITEM_H__ #define __IDO_LOCATION_MENU_ITEM_H__ #include #include "idotimestampmenuitem.h" G_BEGIN_DECLS #define IDO_LOCATION_MENU_ITEM_TYPE (ido_location_menu_item_get_type ()) #define IDO_LOCATION_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IDO_LOCATION_MENU_ITEM_TYPE, IdoLocationMenuItem)) #define IDO_IS_LOCATION_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IDO_LOCATION_MENU_ITEM_TYPE)) typedef struct _IdoLocationMenuItem IdoLocationMenuItem; typedef struct _IdoLocationMenuItemClass IdoLocationMenuItemClass; typedef struct _IdoLocationMenuItemPrivate IdoLocationMenuItemPrivate; struct _IdoLocationMenuItemClass { IdoTimeStampMenuItemClass parent_class; }; /** * A menuitem that indicates a location. * * It contains a primary label giving the location's name and a * right-aligned secondary label showing the location's current time */ struct _IdoLocationMenuItem { /*< private >*/ IdoTimeStampMenuItem parent; IdoLocationMenuItemPrivate * priv; }; GType ido_location_menu_item_get_type (void) G_GNUC_CONST; GtkWidget * ido_location_menu_item_new (void); GtkMenuItem * ido_location_menu_item_new_from_model (GMenuItem * menuitem, GActionGroup * actions); void ido_location_menu_item_set_timezone (IdoLocationMenuItem * menuitem, const char * timezone); void ido_location_menu_item_set_format (IdoLocationMenuItem * menuitem, const char * strftime_fmt); G_END_DECLS #endif ./src/idoswitchmenuitem.c0000644000004100000410000001707514320114711015743 0ustar www-datawww-data/* * A GtkCheckMenuItem that uses a GtkSwitch to show its 'active' property * * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * * Author: Charles Kerr */ #include "config.h" #include "idoswitchmenuitem.h" #include "idoactionhelper.h" static gboolean ido_switch_menu_button_release_event (GtkWidget * widget, GdkEventButton * event); struct _IdoSwitchMenuItemPrivate { GtkWidget * box; GtkWidget * content_area; GtkWidget * label; GtkWidget * image; GtkWidget * switch_w; }; /*** **** Life Cycle ***/ G_DEFINE_TYPE (IdoSwitchMenuItem, ido_switch_menu_item, GTK_TYPE_CHECK_MENU_ITEM) static void ido_switch_menu_item_class_init (IdoSwitchMenuItemClass *klass) { GObjectClass * gobject_class; GtkWidgetClass * widget_class; GtkCheckMenuItemClass * check_class; gobject_class = G_OBJECT_CLASS (klass); g_type_class_add_private (gobject_class, sizeof (IdoSwitchMenuItemPrivate)); widget_class = GTK_WIDGET_CLASS (klass); widget_class->button_release_event = ido_switch_menu_button_release_event; check_class = GTK_CHECK_MENU_ITEM_CLASS (klass); check_class->draw_indicator = NULL; } static void ido_switch_menu_item_init (IdoSwitchMenuItem *item) { IdoSwitchMenuItemPrivate *priv; priv = item->priv = G_TYPE_INSTANCE_GET_PRIVATE (item, IDO_TYPE_SWITCH_MENU_ITEM, IdoSwitchMenuItemPrivate); priv->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); priv->content_area = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); priv->switch_w = gtk_switch_new (); gtk_box_pack_start (GTK_BOX (priv->box), priv->content_area, TRUE, TRUE, 0); gtk_box_pack_end (GTK_BOX (priv->box), priv->switch_w, FALSE, FALSE, 0); gtk_container_add (GTK_CONTAINER (item), priv->box); gtk_widget_show_all (priv->box); g_object_bind_property (item, "active", priv->switch_w, "active", G_BINDING_SYNC_CREATE); } /*** **** Don't popdown the menu immediately after clicking on a switch... **** wait a moment so the user can see the GtkSwitch be toggled. ***/ static gboolean popdown_later_cb (gpointer widget) { GtkWidget * parent = gtk_widget_get_parent (widget); if (GTK_IS_MENU (parent)) { gtk_menu_shell_deactivate (GTK_MENU_SHELL(parent)); } g_object_unref (widget); return FALSE; /* only call this cb once */ } static gboolean ido_switch_menu_button_release_event (GtkWidget * widget, GdkEventButton * event) { gtk_menu_item_activate (GTK_MENU_ITEM(widget)); g_timeout_add (500, popdown_later_cb, g_object_ref(widget)); return TRUE; /* stop the event so that it doesn't trigger popdown() */ } /** * ido_switch_menu_item_new: * * Creates a new #IdoSwitchMenuItem * * Return Value: a new #IdoSwitchMenuItem. **/ GtkWidget * ido_switch_menu_item_new (void) { return g_object_new (IDO_TYPE_SWITCH_MENU_ITEM, NULL); } /** * ido_switch_menu_item_get_content_area: * @item: The #IdoSwitchMenuItem. * * Get the #GtkContainer to add additional widgets into. * * This function is dperecated. * * Return Value: (transfer none): The #GtkContainer to add additional widgets into. **/ GtkContainer * ido_switch_menu_item_get_content_area (IdoSwitchMenuItem * item) { static gboolean warned = FALSE; g_return_val_if_fail (IDO_IS_SWITCH_MENU_ITEM(item), NULL); if (!warned) { g_warning ("%s is deprecated. Please don't use it, especially if you're using" "ido_switch_menu_set_{label,icon}()", G_STRFUNC); warned = TRUE; } return GTK_CONTAINER (item->priv->content_area); } /** * ido_switch_menu_item_set_label: * @item: a #IdoSwitchMenuItem. * @label: a string to set as the label of @item * * Set the label of @item to @label. **/ void ido_switch_menu_item_set_label (IdoSwitchMenuItem *item, const gchar *label) { IdoSwitchMenuItemPrivate *priv; g_return_if_fail (IDO_IS_SWITCH_MENU_ITEM (item)); g_return_if_fail (label != NULL); priv = item->priv; if (priv->label == NULL) { priv->label = gtk_label_new (NULL); gtk_widget_set_halign (priv->label, GTK_ALIGN_START); gtk_widget_show (priv->label); gtk_box_pack_end (GTK_BOX (priv->content_area), priv->label, TRUE, TRUE, 0); } gtk_label_set_text (GTK_LABEL (priv->label), label); } /** * ido_switch_menu_item_set_icon: * @item: a #IdoSwitchMenuItem. * @icon: (allow-none): a #GIcon * * Set the icon of @item to @icon. **/ void ido_switch_menu_item_set_icon (IdoSwitchMenuItem *item, GIcon *icon) { IdoSwitchMenuItemPrivate *priv; g_return_if_fail (IDO_IS_SWITCH_MENU_ITEM (item)); g_return_if_fail (icon == NULL || G_IS_ICON (icon)); priv = item->priv; if (icon) { if (priv->image == NULL) { priv->image = gtk_image_new (); gtk_widget_show (priv->image); gtk_box_pack_start (GTK_BOX (priv->content_area), priv->image, FALSE, FALSE, 0); } gtk_image_set_from_gicon (GTK_IMAGE (priv->image), icon, GTK_ICON_SIZE_MENU); } else if (priv->image) { gtk_image_clear (GTK_IMAGE (priv->image)); } } static void ido_source_menu_item_state_changed (IdoActionHelper *helper, GVariant *state, gpointer user_data) { IdoSwitchMenuItem *item = user_data; if (g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN)) gtk_switch_set_active (GTK_SWITCH (item->priv->switch_w), g_variant_get_boolean (state)); } GtkMenuItem * ido_switch_menu_item_new_from_menu_model (GMenuItem *menuitem, GActionGroup *actions) { GtkMenuItem *item; gchar *label; GVariant *serialized_icon; gchar *action = NULL; item = g_object_new (IDO_TYPE_SWITCH_MENU_ITEM, NULL); if (g_menu_item_get_attribute (menuitem, "label", "s", &label)) { ido_switch_menu_item_set_label (IDO_SWITCH_MENU_ITEM (item), label); g_free (label); } serialized_icon = g_menu_item_get_attribute_value (menuitem, "icon", NULL); if (serialized_icon) { GIcon *icon; icon = g_icon_deserialize (serialized_icon); if (icon) { ido_switch_menu_item_set_icon (IDO_SWITCH_MENU_ITEM (item), icon); g_object_unref (icon); } g_variant_unref (serialized_icon); } if (g_menu_item_get_attribute (menuitem, "action", "s", &action)) { IdoActionHelper *helper; helper = ido_action_helper_new (GTK_WIDGET (item), actions, action, NULL); g_signal_connect (helper, "action-state-changed", G_CALLBACK (ido_source_menu_item_state_changed), item); g_signal_connect_object (item, "activate", G_CALLBACK (ido_action_helper_activate), helper, G_CONNECT_SWAPPED); g_signal_connect_swapped (item, "destroy", G_CALLBACK (g_object_unref), helper); g_free (action); } return item; } ./src/ido.list0000644000004100000410000000002214320114711013466 0ustar www-datawww-dataVOID:POINTER,UINT ./src/idodetaillabel.c0000644000004100000410000002602514320114711015133 0ustar www-datawww-data/* * Copyright 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * * Authors: * Lars Uebernickel */ #include "idodetaillabel.h" #include G_DEFINE_TYPE (IdoDetailLabel, ido_detail_label, GTK_TYPE_WIDGET) struct _IdoDetailLabelPrivate { gchar *text; PangoLayout *layout; gboolean draw_lozenge; }; enum { PROP_0, PROP_TEXT, NUM_PROPERTIES }; static GParamSpec *properties[NUM_PROPERTIES]; static void ido_detail_label_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { IdoDetailLabel *self = IDO_DETAIL_LABEL (object); switch (property_id) { case PROP_TEXT: g_value_set_string (value, self->priv->text); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } static void ido_detail_label_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { IdoDetailLabel *self = IDO_DETAIL_LABEL (object); switch (property_id) { case PROP_TEXT: ido_detail_label_set_text (self, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } static void ido_detail_label_finalize (GObject *object) { IdoDetailLabelPrivate *priv = IDO_DETAIL_LABEL (object)->priv; g_free (priv->text); G_OBJECT_CLASS (ido_detail_label_parent_class)->finalize (object); } static void ido_detail_label_dispose (GObject *object) { IdoDetailLabelPrivate *priv = IDO_DETAIL_LABEL (object)->priv; g_clear_object (&priv->layout); G_OBJECT_CLASS (ido_detail_label_parent_class)->dispose (object); } static void ido_detail_label_ensure_layout (IdoDetailLabel *label) { IdoDetailLabelPrivate *priv = label->priv; if (priv->layout == NULL) { priv->layout = gtk_widget_create_pango_layout (GTK_WIDGET (label), priv->text); pango_layout_set_alignment (priv->layout, PANGO_ALIGN_CENTER); pango_layout_set_ellipsize (priv->layout, PANGO_ELLIPSIZE_END); pango_layout_set_height (priv->layout, -1); // TODO update layout on "style-updated" and "direction-changed" } } static void cairo_lozenge (cairo_t *cr, double x, double y, double w, double h, double radius) { double x1 = x + w - radius; double x2 = x + radius; double y1 = y + radius; double y2 = y + h - radius; cairo_move_to (cr, x + radius, y); cairo_arc (cr, x1, y1, radius, G_PI * 1.5, G_PI * 2); cairo_arc (cr, x1, y2, radius, 0, G_PI * 0.5); cairo_arc (cr, x2, y2, radius, G_PI * 0.5, G_PI); cairo_arc (cr, x2, y1, radius, G_PI, G_PI * 1.5); } static PangoFontMetrics * gtk_widget_get_font_metrics (GtkWidget *widget, PangoContext *context) { PangoFontDescription *font; PangoFontMetrics *metrics; gtk_style_context_get (gtk_widget_get_style_context (widget), gtk_widget_get_state_flags (widget), "font", &font, NULL); metrics = pango_context_get_metrics (context, font, pango_context_get_language (context)); pango_font_description_free (font); return metrics; } static gint ido_detail_label_get_minimum_text_width (IdoDetailLabel *label) { IdoDetailLabelPrivate *priv = label->priv; PangoContext *context; PangoFontMetrics *metrics; gint char_width; gint w; context = pango_layout_get_context (priv->layout); metrics = gtk_widget_get_font_metrics (GTK_WIDGET (label), context); char_width = pango_font_metrics_get_approximate_digit_width (metrics); w = 2 * char_width / PANGO_SCALE; pango_font_metrics_unref (metrics); return w; } static gboolean ido_detail_label_draw (GtkWidget *widget, cairo_t *cr) { IdoDetailLabel *label = IDO_DETAIL_LABEL (widget); IdoDetailLabelPrivate *priv = IDO_DETAIL_LABEL (widget)->priv; PangoRectangle extents; GtkAllocation allocation; double x, w, h, radius; GdkRGBA color; if (!priv->text || !*priv->text) return TRUE; gtk_widget_get_allocation (widget, &allocation); ido_detail_label_ensure_layout (IDO_DETAIL_LABEL (widget)); pango_layout_get_extents (priv->layout, NULL, &extents); pango_extents_to_pixels (&extents, NULL); h = MIN (allocation.height, extents.height); radius = floor (h / 2.0); w = MAX (ido_detail_label_get_minimum_text_width (label), extents.width) + 2.0 * radius; x = allocation.width - w; pango_layout_set_width (priv->layout, (allocation.width - 2 * radius) * PANGO_SCALE); pango_layout_get_extents (priv->layout, NULL, &extents); pango_extents_to_pixels (&extents, NULL); gtk_style_context_get_color (gtk_widget_get_style_context (widget), gtk_widget_get_state_flags (widget), &color); gdk_cairo_set_source_rgba (cr, &color); cairo_set_line_width (cr, 1.0); cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); if (priv->draw_lozenge) cairo_lozenge (cr, x, 0.0, w, h, radius); cairo_move_to (cr, x + radius, (allocation.height - extents.height) / 2.0); pango_cairo_layout_path (cr, priv->layout); cairo_fill (cr); return TRUE; } static void ido_detail_label_get_preferred_width (GtkWidget *widget, gint *minimum, gint *natural) { IdoDetailLabelPrivate *priv = IDO_DETAIL_LABEL (widget)->priv; PangoRectangle extents; double radius; ido_detail_label_ensure_layout (IDO_DETAIL_LABEL (widget)); pango_layout_get_extents (priv->layout, NULL, &extents); pango_extents_to_pixels (&extents, NULL); radius = floor (extents.height / 2.0); *minimum = ido_detail_label_get_minimum_text_width (IDO_DETAIL_LABEL (widget)) + 2.0 * radius; *natural = MAX (*minimum, extents.width + 2.0 * radius); } static void ido_detail_label_get_preferred_height (GtkWidget *widget, gint *minimum, gint *natural) { IdoDetailLabelPrivate *priv = IDO_DETAIL_LABEL (widget)->priv; PangoContext *context; PangoFontMetrics *metrics; PangoRectangle extents; ido_detail_label_ensure_layout (IDO_DETAIL_LABEL (widget)); pango_layout_get_extents (priv->layout, NULL, &extents); pango_extents_to_pixels (&extents, NULL); context = pango_layout_get_context (priv->layout); metrics = gtk_widget_get_font_metrics (widget, context); *minimum = *natural = (pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent (metrics)) / PANGO_SCALE; pango_font_metrics_unref (metrics); } static void ido_detail_label_class_init (IdoDetailLabelClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->get_property = ido_detail_label_get_property; object_class->set_property = ido_detail_label_set_property; object_class->finalize = ido_detail_label_finalize; object_class->dispose = ido_detail_label_dispose; widget_class->draw = ido_detail_label_draw; widget_class->get_preferred_width = ido_detail_label_get_preferred_width; widget_class->get_preferred_height = ido_detail_label_get_preferred_height; g_type_class_add_private (klass, sizeof (IdoDetailLabelPrivate)); properties[PROP_TEXT] = g_param_spec_string ("text", "Text", "The text of the label", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, NUM_PROPERTIES, properties); } static void ido_detail_label_init (IdoDetailLabel *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, IDO_TYPE_DETAIL_LABEL, IdoDetailLabelPrivate); gtk_widget_set_has_window (GTK_WIDGET (self), FALSE); } GtkWidget * ido_detail_label_new (const gchar *label) { return g_object_new (IDO_TYPE_DETAIL_LABEL, "text", label, NULL); } const gchar * ido_detail_label_get_text (IdoDetailLabel *label) { g_return_val_if_fail (IDO_IS_DETAIL_LABEL (label), NULL); return label->priv->text; } /* collapse_whitespace: * @str: the source string * * Collapses all occurences of consecutive whitespace charactes in @str * into a single space. * * Returns: (transfer full): a newly-allocated string */ static gchar * collapse_whitespace (const gchar *str) { GString *result; gboolean in_space = FALSE; if (str == NULL) return NULL; result = g_string_new (""); while (*str) { gunichar c = g_utf8_get_char_validated (str, -1); if (c == (gunichar) -1) break; if (!g_unichar_isspace (c)) { g_string_append_unichar (result, c); in_space = FALSE; } else if (!in_space) { g_string_append_c (result, ' '); in_space = TRUE; } str = g_utf8_next_char (str); } return g_string_free (result, FALSE); } static void ido_detail_label_set_text_impl (IdoDetailLabel *label, const gchar *text, gboolean draw_lozenge) { IdoDetailLabelPrivate * priv = label->priv; g_clear_object (&priv->layout); g_free (priv->text); priv->text = g_strdup (text); priv->draw_lozenge = draw_lozenge; g_object_notify_by_pspec (G_OBJECT (label), properties[PROP_TEXT]); gtk_widget_queue_resize (GTK_WIDGET (label)); } void ido_detail_label_set_text (IdoDetailLabel *label, const gchar *text) { gchar *str; g_return_if_fail (IDO_IS_DETAIL_LABEL (label)); str = collapse_whitespace (text); ido_detail_label_set_text_impl (label, str, FALSE); g_free (str); } void ido_detail_label_set_count (IdoDetailLabel *label, gint count) { gchar *text; g_return_if_fail (IDO_IS_DETAIL_LABEL (label)); text = g_strdup_printf ("%d", count); ido_detail_label_set_text_impl (label, text, TRUE); g_free (text); } ./src/idoactionhelper.h0000644000004100000410000000407614320114711015355 0ustar www-datawww-data/* * Copyright 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * * Authors: * Lars Uebernickel */ #ifndef __IDO_ACTION_HELPER_H__ #define __IDO_ACTION_HELPER_H__ #include #define IDO_TYPE_ACTION_HELPER (ido_action_helper_get_type ()) #define IDO_ACTION_HELPER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), IDO_TYPE_ACTION_HELPER, IdoActionHelper)) #define IDO_IS_ACTION_HELPER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), IDO_TYPE_ACTION_HELPER)) typedef struct _IdoActionHelper IdoActionHelper; GType ido_menu_item_get_type (void); IdoActionHelper * ido_action_helper_new (GtkWidget *widget, GActionGroup *action_group, const gchar *action_name, GVariant *target); GtkWidget * ido_action_helper_get_widget (IdoActionHelper *helper); GVariant * ido_action_helper_get_action_target (IdoActionHelper *helper); void ido_action_helper_activate (IdoActionHelper *helper); void ido_action_helper_activate_with_parameter (IdoActionHelper *helper, GVariant *parameter); void ido_action_helper_change_action_state (IdoActionHelper *helper, GVariant *state); #endif ./src/idoswitchmenuitem.h0000644000004100000410000000516014320114711015740 0ustar www-datawww-data/* * A GtkCheckMenuItem that uses a GtkSwitch to show its 'active' property. * * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * * Author: Charles Kerr */ #ifndef __IDO_SWITCH_MENU_ITEM_H__ #define __IDO_SWITCH_MENU_ITEM_H__ #include G_BEGIN_DECLS #define IDO_TYPE_SWITCH_MENU_ITEM (ido_switch_menu_item_get_type ()) #define IDO_SWITCH_MENU_ITEM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), IDO_TYPE_SWITCH_MENU_ITEM, IdoSwitchMenuItem)) #define IDO_SWITCH_MENU_ITEM_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), IDO_TYPE_SWITCH_MENU_ITEM, IdoSwitchMenuItemClass)) #define IDO_IS_SWITCH_MENU_ITEM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), IDO_TYPE_SWITCH_MENU_ITEM)) #define IDO_IS_SWITCH_MENU_ITEM_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), IDO_TYPE_SWITCH_MENU_ITEM)) #define IDO_SWITCH_MENU_ITEM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), IDO_TYPE_SWITCH_MENU_ITEM, IdoSwitchMenuItemClass)) typedef struct _IdoSwitchMenuItem IdoSwitchMenuItem; typedef struct _IdoSwitchMenuItemClass IdoSwitchMenuItemClass; typedef struct _IdoSwitchMenuItemPrivate IdoSwitchMenuItemPrivate; struct _IdoSwitchMenuItem { GtkCheckMenuItem parent_instance; IdoSwitchMenuItemPrivate *priv; }; struct _IdoSwitchMenuItemClass { GtkCheckMenuItemClass parent_class; }; GType ido_switch_menu_item_get_type (void) G_GNUC_CONST; GtkWidget *ido_switch_menu_item_new (void); GtkContainer *ido_switch_menu_item_get_content_area (IdoSwitchMenuItem * item); GtkMenuItem * ido_switch_menu_item_new_from_menu_model (GMenuItem *menuitem, GActionGroup *actions); void ido_switch_menu_item_set_label (IdoSwitchMenuItem *item, const gchar *label); void ido_switch_menu_item_set_icon (IdoSwitchMenuItem *item, GIcon *icon); G_END_DECLS #endif /* __IDO_SWITCH_MENU_ITEM_H__ */ ./src/idoprogressmenuitem.c0000644000004100000410000000621114320114711016274 0ustar www-datawww-data/* * Copyright 2013 Canonical Ltd. * * Authors: * Charles Kerr * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "idoprogressmenuitem.h" #include "idobasicmenuitem.h" #include "idoactionhelper.h" static void on_progress_action_state_changed (IdoActionHelper * helper, GVariant * state, gpointer unused G_GNUC_UNUSED) { IdoBasicMenuItem * ido_menu_item; char * str; ido_menu_item = IDO_BASIC_MENU_ITEM (ido_action_helper_get_widget (helper)); g_return_if_fail (ido_menu_item != NULL); g_return_if_fail (g_variant_is_of_type (state, G_VARIANT_TYPE_UINT32)); str = g_strdup_printf ("%"G_GUINT32_FORMAT"%%", g_variant_get_uint32 (state)); ido_basic_menu_item_set_secondary_text (ido_menu_item, str); g_free (str); } /** * ido_progress_menu_item_new_from_model: * @menu_item: the corresponding menuitem * @actions: action group to tell when this GtkMenuItem is activated * * Creates a new progress menuitem with properties initialized from * the menuitem's attributes. * * If the menuitem's 'action' attribute is set, trigger that action * in @actions when this IdoBasicMenuItem is activated. */ GtkMenuItem * ido_progress_menu_item_new_from_model (GMenuItem * menu_item, GActionGroup * actions) { guint i; guint n; gchar * str; IdoBasicMenuItem * ido_menu_item; GParameter parameters[4]; /* create the ido menuitem */; n = 0; if (g_menu_item_get_attribute (menu_item, "label", "s", &str)) { GParameter p = { "text", G_VALUE_INIT }; g_value_init (&p.value, G_TYPE_STRING); g_value_take_string (&p.value, str); parameters[n++] = p; } g_assert (n <= G_N_ELEMENTS (parameters)); ido_menu_item = g_object_newv (IDO_TYPE_BASIC_MENU_ITEM, n, parameters); for (i=0; i> xgen-gtbh \ && (cmp -s xgen-gtbh idotypebuiltins.h || cp xgen-gtbh idotypebuiltins.h ) \ && rm -f xgen-gtbh && echo timestamp > $(@F) idotypebuiltins.c: stamp-idotypebuiltins.h ( cd $(srcdir) && $(GLIB_MKENUMS) --template idotypebuiltins.c.template \ $(sources_h) ) > xgen-gtbc \ && cp xgen-gtbc idotypebuiltins.c && rm -f xgen-gtbc INCLUDES = \ -I$(srcdir) \ -I$(top_srcdir) \ -DG_LOG_DOMAIN=\"IDO\" \ -DPREFIX=\"$(prefix)"\" \ -DLIBDIR=\"$(libdir)"\" \ -DG_DISABLE_DEPRECATED \ -DGDK_PIXBUF_DISABLE_DEPRECATED \ -DGDK_DISABLE_DEPRECATED AM_CPPFLAGS = \ $(GCC_FLAGS) \ $(GTK_CFLAGS) \ $(MAINTAINER_CFLAGS) \ -Wall -Wextra -Wno-unused-parameter -Wno-error=deprecated-declarations AM_CFLAGS = \ $(COVERAGE_CFLAGS) libido_0_1_la_SOURCES = \ libido.c \ idotypebuiltins.c \ idocalendarmenuitem.c \ idoalarmmenuitem.c \ idoentrymenuitem.c \ idomessagedialog.c \ idorange.c \ idoscalemenuitem.c \ idoswitchmenuitem.c \ idotimeline.c \ idomenuitemfactory.c \ idoactionhelper.c \ idousermenuitem.c \ idomediaplayermenuitem.c \ idoplaybackmenuitem.c \ idoappointmentmenuitem.c \ idobasicmenuitem.c \ idoprogressmenuitem.c \ idotimestampmenuitem.c \ idolocationmenuitem.c \ idoapplicationmenuitem.c \ idodetaillabel.c \ idosourcemenuitem.c libido3_0_1_la_SOURCES = $(libido_0_1_la_SOURCES) libidoincludedir=$(includedir)/libido$(VER)-0.1/libido libidoinclude_HEADERS = \ idocalendarmenuitem.h \ idoentrymenuitem.h \ idomessagedialog.h \ idorange.h \ idoscalemenuitem.h \ idoswitchmenuitem.h \ idotimeline.h \ libido.h libido_0_1_la_LIBADD = $(GTK_LIBS) $(LIBM) libido_0_1_la_LDFLAGS = \ $(GTK_LT_LDFLAGS) \ $(COVERAGE_LDFLAGS) \ -no-undefined \ -export-symbols-regex "^[^_].*" libido3_0_1_la_LIBADD = $(libido_0_1_la_LIBADD) libido3_0_1_la_LDFLAGS = \ $(libido_0_1_la_LDFLAGS) DISTCLEANFILES = \ stamp-idotypebuiltins.h \ idotypebuiltins.h \ idotypebuiltins.c -include $(INTROSPECTION_MAKEFILE) INTROSPECTION_GIRS = INTROSPECTION_SCANNER_ARGS = \ --symbol-prefix=ido \ --warn-all \ --identifier-prefix=Ido if HAVE_INTROSPECTION Ido3-0.1.gir: libido3-0.1.la Ido3_0_1_gir_INCLUDES = Gtk-3.0 Ido3_0_1_gir_CFLAGS = Ido3_0_1_gir_LIBS = libido3-0.1.la Ido3_0_1_gir_FILES = \ idocalendarmenuitem.h \ idoentrymenuitem.h \ idomessagedialog.h \ idorange.h \ idoscalemenuitem.h \ idoswitchmenuitem.h \ idotimeline.h \ $(libido_0_1_la_SOURCES) Ido3_0_1_gir_NAMESPACE = Ido3 Ido3_0_1_gir_VERSION = 0.1 Ido3_0_1_gir_SCANNER_FLAGS = $(INTROSPECTION_SCANNER_ARGS) INTROSPECTION_GIRS += Ido3-0.1.gir girdir = $(datadir)/gir-1.0 gir_DATA = $(INTROSPECTION_GIRS) typelibdir = $(libdir)/girepository-1.0 typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib) CLEANFILES += $(gir_DATA) $(typelib_DATA) endif if HAVE_INTROSPECTION vapidir = $(datadir)/vala/vapi vapi_DATA = Ido3-0.1.vapi Ido3-0.1.vapi: Ido3-0.1.gir $(VALA_API_GEN) --library=Ido3-0.1 \ --pkg gtk+-3.0 \ $< CLEANFILES += $(vapi_DATA) endif ./src/idousermenuitem.h0000644000004100000410000000557414320114711015426 0ustar www-datawww-data/* Copyright 2011 Canonical Ltd. Authors: Conor Curran This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef __IDO_USER_MENU_ITEM_H__ #define __IDO_USER_MENU_ITEM_H__ #include G_BEGIN_DECLS #define IDO_USER_MENU_ITEM_TYPE (ido_user_menu_item_get_type ()) #define IDO_USER_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IDO_USER_MENU_ITEM_TYPE, IdoUserMenuItem)) #define IDO_USER_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IDO_USER_MENU_ITEM_TYPE, IdoUserMenuItemClass)) #define IS_IDO_USER_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IDO_USER_MENU_ITEM_TYPE)) #define IS_IDO_USER_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IDO_USER_MENU_ITEM_TYPE)) #define IDO_USER_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IDO_USER_MENU_ITEM_TYPE, IdoUserMenuItemClass)) typedef struct _IdoUserMenuItem IdoUserMenuItem; typedef struct _IdoUserMenuItemClass IdoUserMenuItemClass; typedef struct _IdoUserMenuItemPrivate IdoUserMenuItemPrivate; /* property keys */ #define IDO_USER_MENU_ITEM_PROP_LABEL "label" #define IDO_USER_MENU_ITEM_PROP_ICON_FILENAME "icon-filename" #define IDO_USER_MENU_ITEM_PROP_IS_LOGGED_IN "is-logged-in" #define IDO_USER_MENU_ITEM_PROP_IS_CURRENT_USER "is-current-user" struct _IdoUserMenuItemClass { GtkMenuItemClass parent_class; }; struct _IdoUserMenuItem { /*< private >*/ GtkMenuItem parent; IdoUserMenuItemPrivate * priv; }; GType ido_user_menu_item_get_type (void) G_GNUC_CONST; GtkWidget* ido_user_menu_item_new(void); void ido_user_menu_item_set_icon (IdoUserMenuItem * self, GIcon * icon); void ido_user_menu_item_set_icon_from_file (IdoUserMenuItem * self, const char * filename); void ido_user_menu_item_set_logged_in (IdoUserMenuItem * self, gboolean is_logged_in); void ido_user_menu_item_set_current_user (IdoUserMenuItem * self, gboolean is_current_user); void ido_user_menu_item_set_label (IdoUserMenuItem * self, const char * label); GtkMenuItem * ido_user_menu_item_new_from_model (GMenuItem *menuitem, GActionGroup *actions); GtkMenuItem * ido_guest_menu_item_new_from_model (GMenuItem *menuitem, GActionGroup *actions); G_END_DECLS #endif ./src/idoappointmentmenuitem.h0000644000004100000410000000177514320114711017005 0ustar www-datawww-data/** * Copyright 2013 Canonical Ltd. * * Authors: * Charles Kerr * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifndef __IDO_APPOINTMENT_MENU_ITEM_H__ #define __IDO_APPOINTMENT_MENU_ITEM_H__ #include G_BEGIN_DECLS GtkMenuItem * ido_appointment_menu_item_new_from_model (GMenuItem * menuitem, GActionGroup * actions); G_END_DECLS #endif ./src/idotimeline.c0000644000004100000410000004677414320114711014514 0ustar www-datawww-data/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */ /* gtktimeline.c * * Copyright (C) 2007 Carlos Garnacho * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "idotimeline.h" #include "idotypebuiltins.h" #include #include #define IDO_TIMELINE_GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), IDO_TYPE_TIMELINE, IdoTimelinePriv)) #define MSECS_PER_SEC 1000 #define FRAME_INTERVAL(nframes) (MSECS_PER_SEC / nframes) #define DEFAULT_FPS 30 typedef struct IdoTimelinePriv IdoTimelinePriv; struct IdoTimelinePriv { guint duration; guint fps; guint source_id; GTimer *timer; gdouble progress; gdouble last_progress; GdkScreen *screen; guint animations_enabled : 1; guint loop : 1; guint direction : 1; }; enum { PROP_0, PROP_FPS, PROP_DURATION, PROP_LOOP, PROP_DIRECTION, PROP_SCREEN }; enum { STARTED, PAUSED, FINISHED, FRAME, LAST_SIGNAL }; static guint signals [LAST_SIGNAL] = { 0, }; static void ido_timeline_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void ido_timeline_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void ido_timeline_finalize (GObject *object); G_DEFINE_TYPE (IdoTimeline, ido_timeline, G_TYPE_OBJECT) static void ido_timeline_class_init (IdoTimelineClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = ido_timeline_set_property; object_class->get_property = ido_timeline_get_property; object_class->finalize = ido_timeline_finalize; g_object_class_install_property (object_class, PROP_FPS, g_param_spec_uint ("fps", "FPS", "Frames per second for the timeline", 1, G_MAXUINT, DEFAULT_FPS, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_DURATION, g_param_spec_uint ("duration", "Animation Duration", "Animation Duration", 0, G_MAXUINT, 0, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_LOOP, g_param_spec_boolean ("loop", "Loop", "Whether the timeline loops or not", FALSE, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_DIRECTION, g_param_spec_enum ("direction", "Direction", "Whether the timeline moves forward or backward in time", IDO_TYPE_TIMELINE_DIRECTION, IDO_TIMELINE_DIRECTION_FORWARD, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_SCREEN, g_param_spec_object ("screen", "Screen", "Screen to get the settings from", GDK_TYPE_SCREEN, G_PARAM_READWRITE)); /** * IdoTimeline::started: * @timeline: The #IdoTimeline emitting the signal. * * The ::started signal is emitted when the timeline starts. */ signals[STARTED] = g_signal_new ("started", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (IdoTimelineClass, started), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * IdoTimeline::paused: * @timeline: The #IdoTimeline emitting the signal. * * The ::paused signal is emitted when the timeline pauses. */ signals[PAUSED] = g_signal_new ("paused", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (IdoTimelineClass, paused), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * IdoTimeline::finished: * @timeline: The #IdoTimeline emitting the signal. * * The ::paused signal is emitted when the timeline finishes. */ signals[FINISHED] = g_signal_new ("finished", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (IdoTimelineClass, finished), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * IdoTimeline::frame: * @timeline: The #IdoTimeline emitting the signal. * @progress: The progress position for this frame from 0.0 (start) to 1.0 (end). * * The ::frame signal is emitted when a frame should be drawn. */ signals[FRAME] = g_signal_new ("frame", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (IdoTimelineClass, frame), NULL, NULL, g_cclosure_marshal_VOID__DOUBLE, G_TYPE_NONE, 1, G_TYPE_DOUBLE); g_type_class_add_private (klass, sizeof (IdoTimelinePriv)); } static void ido_timeline_init (IdoTimeline *timeline) { IdoTimelinePriv *priv; priv = IDO_TIMELINE_GET_PRIV (timeline); priv->fps = DEFAULT_FPS; priv->duration = 0.0; priv->direction = IDO_TIMELINE_DIRECTION_FORWARD; priv->screen = gdk_screen_get_default (); priv->last_progress = 0; } static void ido_timeline_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { IdoTimeline *timeline; timeline = IDO_TIMELINE (object); switch (prop_id) { case PROP_FPS: ido_timeline_set_fps (timeline, g_value_get_uint (value)); break; case PROP_DURATION: ido_timeline_set_duration (timeline, g_value_get_uint (value)); break; case PROP_LOOP: ido_timeline_set_loop (timeline, g_value_get_boolean (value)); break; case PROP_DIRECTION: ido_timeline_set_direction (timeline, g_value_get_enum (value)); break; case PROP_SCREEN: ido_timeline_set_screen (timeline, (GdkScreen*)g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void ido_timeline_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { IdoTimeline *timeline; IdoTimelinePriv *priv; timeline = IDO_TIMELINE (object); priv = IDO_TIMELINE_GET_PRIV (timeline); switch (prop_id) { case PROP_FPS: g_value_set_uint (value, priv->fps); break; case PROP_DURATION: g_value_set_uint (value, priv->duration); break; case PROP_LOOP: g_value_set_boolean (value, priv->loop); break; case PROP_DIRECTION: g_value_set_enum (value, priv->direction); break; case PROP_SCREEN: g_value_set_object (value, priv->screen); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void ido_timeline_finalize (GObject *object) { IdoTimelinePriv *priv; priv = IDO_TIMELINE_GET_PRIV (object); if (priv->source_id) { g_source_remove (priv->source_id); priv->source_id = 0; } if (priv->timer) g_timer_destroy (priv->timer); G_OBJECT_CLASS (ido_timeline_parent_class)->finalize (object); } static gboolean ido_timeline_run_frame (IdoTimeline *timeline) { IdoTimelinePriv *priv; gdouble delta_progress, progress; guint elapsed_time; priv = IDO_TIMELINE_GET_PRIV (timeline); elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000); g_timer_start (priv->timer); if (priv->animations_enabled) { delta_progress = (gdouble) elapsed_time / priv->duration; progress = priv->last_progress; if (priv->direction == IDO_TIMELINE_DIRECTION_BACKWARD) progress -= delta_progress; else progress += delta_progress; priv->last_progress = progress; progress = CLAMP (progress, 0., 1.); } else progress = (priv->direction == IDO_TIMELINE_DIRECTION_FORWARD) ? 1.0 : 0.0; priv->progress = progress; g_signal_emit (timeline, signals [FRAME], 0, progress); if ((priv->direction == IDO_TIMELINE_DIRECTION_FORWARD && progress == 1.0) || (priv->direction == IDO_TIMELINE_DIRECTION_BACKWARD && progress == 0.0)) { if (!priv->loop) { if (priv->source_id) { g_source_remove (priv->source_id); priv->source_id = 0; } g_timer_stop (priv->timer); g_signal_emit (timeline, signals [FINISHED], 0); return FALSE; } else ido_timeline_rewind (timeline); } return TRUE; } /** * ido_timeline_new: * @duration: duration in milliseconds for the timeline * * Creates a new #IdoTimeline with the specified number of frames. * * Return Value: the newly created #IdoTimeline **/ IdoTimeline * ido_timeline_new (guint duration) { return g_object_new (IDO_TYPE_TIMELINE, "duration", duration, NULL); } /** * ido_timeline_new_for_screen: * @duration: duration in milliseconds for the timeline * @screen: Screen to start on. * * Creates a new #IdoTimeline with the specified number of frames on the given screen. * * Return Value: the newly created #IdoTimeline **/ IdoTimeline * ido_timeline_new_for_screen (guint duration, GdkScreen *screen) { return g_object_new (IDO_TYPE_TIMELINE, "duration", duration, "screen", screen, NULL); } /** * ido_timeline_start: * @timeline: A #IdoTimeline * * Runs the timeline from the current frame. **/ void ido_timeline_start (IdoTimeline *timeline) { IdoTimelinePriv *priv; gboolean enable_animations = FALSE; g_return_if_fail (IDO_IS_TIMELINE (timeline)); priv = IDO_TIMELINE_GET_PRIV (timeline); if (!priv->source_id) { if (priv->timer) g_timer_continue (priv->timer); else priv->timer = g_timer_new (); /* sanity check; CID: 12651 */ priv->fps = priv->fps > 0 ? priv->fps : DEFAULT_FPS; if (priv->screen) { #if 0 GtkSettings *settings = gtk_settings_get_for_screen (priv->screen); g_object_get (settings, "ido-enable-animations", &enable_animations, NULL); #else // XXX enable_animations = TRUE; #endif } priv->animations_enabled = (enable_animations == TRUE); g_signal_emit (timeline, signals [STARTED], 0); if (enable_animations) priv->source_id = gdk_threads_add_timeout (FRAME_INTERVAL (priv->fps), (GSourceFunc) ido_timeline_run_frame, timeline); else priv->source_id = gdk_threads_add_idle ((GSourceFunc) ido_timeline_run_frame, timeline); } } /** * ido_timeline_pause: * @timeline: A #IdoTimeline * * Pauses the timeline. **/ void ido_timeline_pause (IdoTimeline *timeline) { IdoTimelinePriv *priv; g_return_if_fail (IDO_IS_TIMELINE (timeline)); priv = IDO_TIMELINE_GET_PRIV (timeline); if (priv->source_id) { g_timer_stop (priv->timer); g_source_remove (priv->source_id); priv->source_id = 0; g_signal_emit (timeline, signals [PAUSED], 0); } } /** * ido_timeline_rewind: * @timeline: A #IdoTimeline * * Rewinds the timeline. **/ void ido_timeline_rewind (IdoTimeline *timeline) { IdoTimelinePriv *priv; g_return_if_fail (IDO_IS_TIMELINE (timeline)); priv = IDO_TIMELINE_GET_PRIV (timeline); if (ido_timeline_get_direction(timeline) != IDO_TIMELINE_DIRECTION_FORWARD) priv->progress = priv->last_progress = 1.; else priv->progress = priv->last_progress = 0.; /* reset timer */ if (priv->timer) { g_timer_start (priv->timer); if (!priv->source_id) g_timer_stop (priv->timer); } } /** * ido_timeline_is_running: * @timeline: A #IdoTimeline * * Returns whether the timeline is running or not. * * Return Value: %TRUE if the timeline is running **/ gboolean ido_timeline_is_running (IdoTimeline *timeline) { IdoTimelinePriv *priv; g_return_val_if_fail (IDO_IS_TIMELINE (timeline), FALSE); priv = IDO_TIMELINE_GET_PRIV (timeline); return (priv->source_id != 0); } /** * ido_timeline_get_fps: * @timeline: A #IdoTimeline * * Returns the number of frames per second. * * Return Value: frames per second **/ guint ido_timeline_get_fps (IdoTimeline *timeline) { IdoTimelinePriv *priv; g_return_val_if_fail (IDO_IS_TIMELINE (timeline), 1); priv = IDO_TIMELINE_GET_PRIV (timeline); return priv->fps; } /** * ido_timeline_set_fps: * @timeline: A #IdoTimeline * @fps: frames per second * * Sets the number of frames per second that * the timeline will play. **/ void ido_timeline_set_fps (IdoTimeline *timeline, guint fps) { IdoTimelinePriv *priv; g_return_if_fail (IDO_IS_TIMELINE (timeline)); g_return_if_fail (fps > 0); priv = IDO_TIMELINE_GET_PRIV (timeline); /* Coverity CID: 12650/12651: guard against division by 0. */ priv->fps = fps > 0 ? fps : priv->fps; if (ido_timeline_is_running (timeline)) { g_source_remove (priv->source_id); priv->source_id = gdk_threads_add_timeout (FRAME_INTERVAL (priv->fps), (GSourceFunc) ido_timeline_run_frame, timeline); } g_object_notify (G_OBJECT (timeline), "fps"); } /** * ido_timeline_get_loop: * @timeline: A #IdoTimeline * * Returns whether the timeline loops to the * beginning when it has reached the end. * * Return Value: %TRUE if the timeline loops **/ gboolean ido_timeline_get_loop (IdoTimeline *timeline) { IdoTimelinePriv *priv; g_return_val_if_fail (IDO_IS_TIMELINE (timeline), FALSE); priv = IDO_TIMELINE_GET_PRIV (timeline); return priv->loop; } /** * ido_timeline_set_loop: * @timeline: A #IdoTimeline * @loop: %TRUE to make the timeline loop * * Sets whether the timeline loops to the beginning * when it has reached the end. **/ void ido_timeline_set_loop (IdoTimeline *timeline, gboolean loop) { IdoTimelinePriv *priv; g_return_if_fail (IDO_IS_TIMELINE (timeline)); priv = IDO_TIMELINE_GET_PRIV (timeline); if (loop != priv->loop) { priv->loop = loop; g_object_notify (G_OBJECT (timeline), "loop"); } } /** * ido_timeline_set_duration: * @timeline: A #IdoTimeline * @duration: Duration in milliseconds. * * Set the animation duration. */ void ido_timeline_set_duration (IdoTimeline *timeline, guint duration) { IdoTimelinePriv *priv; g_return_if_fail (IDO_IS_TIMELINE (timeline)); priv = IDO_TIMELINE_GET_PRIV (timeline); if (duration != priv->duration) { priv->duration = duration; g_object_notify (G_OBJECT (timeline), "duration"); } } /** * ido_timeline_get_duration: * @timeline: A #IdoTimeline * * Set the animation duration. * * Return Value: Duration in milliseconds. */ guint ido_timeline_get_duration (IdoTimeline *timeline) { IdoTimelinePriv *priv; g_return_val_if_fail (IDO_IS_TIMELINE (timeline), 0); priv = IDO_TIMELINE_GET_PRIV (timeline); return priv->duration; } /** * ido_timeline_set_direction: * @timeline: A #IdoTimeline * @direction: direction * * Sets the direction of the timeline. **/ void ido_timeline_set_direction (IdoTimeline *timeline, IdoTimelineDirection direction) { IdoTimelinePriv *priv; g_return_if_fail (IDO_IS_TIMELINE (timeline)); priv = IDO_TIMELINE_GET_PRIV (timeline); if (direction != priv->direction) { priv->direction = direction; g_object_notify (G_OBJECT (timeline), "direction"); } } /** * ido_timeline_get_direction: * @timeline: A #IdoTimeline * * Returns the direction of the timeline. * * Return Value: direction **/ IdoTimelineDirection ido_timeline_get_direction (IdoTimeline *timeline) { IdoTimelinePriv *priv; g_return_val_if_fail (IDO_IS_TIMELINE (timeline), IDO_TIMELINE_DIRECTION_FORWARD); priv = IDO_TIMELINE_GET_PRIV (timeline); return priv->direction; } /** * ido_timeline_set_screen: * @timeline: A #IdoTimeline * @screen: A #GdkScreen to use * * Set the screen the timeline is running on. */ void ido_timeline_set_screen (IdoTimeline *timeline, GdkScreen *screen) { IdoTimelinePriv *priv; g_return_if_fail (IDO_IS_TIMELINE (timeline)); g_return_if_fail (GDK_IS_SCREEN (screen)); priv = IDO_TIMELINE_GET_PRIV (timeline); if (priv->screen) g_object_unref (priv->screen); priv->screen = g_object_ref (screen); g_object_notify (G_OBJECT (timeline), "screen"); } /** * ido_timeline_get_screen: * @timeline: A #IdoTimeline * * Get the screen this timeline is running on. * * Return Value: (transfer none): The #GdkScreen this timeline is running on. */ GdkScreen * ido_timeline_get_screen (IdoTimeline *timeline) { IdoTimelinePriv *priv; g_return_val_if_fail (IDO_IS_TIMELINE (timeline), NULL); priv = IDO_TIMELINE_GET_PRIV (timeline); return priv->screen; } /** * ido_timeline_get_progress: * @timeline: A #IdoTimeline * * Get the progress on the timeline. * * Return Value: The progress from 0.0 (start) to 1.0 (end) */ gdouble ido_timeline_get_progress (IdoTimeline *timeline) { IdoTimelinePriv *priv; g_return_val_if_fail (IDO_IS_TIMELINE (timeline), 0.); priv = IDO_TIMELINE_GET_PRIV (timeline); return priv->progress; } /** * ido_timeline_set_progress: * @timeline: A #IdoTimeline * @progress: The progress from 0.0 (start) to 1.0 (end) * * Set the progress on the timeline. */ void ido_timeline_set_progress (IdoTimeline *timeline, gdouble progress) { IdoTimelinePriv *priv; g_return_if_fail (IDO_IS_TIMELINE (timeline)); priv = IDO_TIMELINE_GET_PRIV (timeline); if (priv->source_id) { g_timer_stop (priv->timer); g_source_remove (priv->source_id); priv->source_id = 0; } priv->progress = priv->last_progress = progress; ido_timeline_start (timeline); } /** * ido_timeline_calculate_progress: * @linear_progress: The progress from 0.0 (start) to 1.0 (end) * @progress_type: The progress transform to apply * * Transform a linear progress position using the given transform. * * Return Value: the progress position using the provided transform. */ gdouble ido_timeline_calculate_progress (gdouble linear_progress, IdoTimelineProgressType progress_type) { gdouble progress; progress = linear_progress; switch (progress_type) { case IDO_TIMELINE_PROGRESS_LINEAR: break; case IDO_TIMELINE_PROGRESS_SINUSOIDAL: progress = sinf ((progress * G_PI) / 2); break; case IDO_TIMELINE_PROGRESS_EXPONENTIAL: progress *= progress; break; case IDO_TIMELINE_PROGRESS_EASE_IN_EASE_OUT: { progress *= 2; if (progress < 1) progress = pow (progress, 3) / 2; else progress = (pow (progress - 2, 3) + 2) / 2; } } return progress; } ./autogen.sh0000755000004100000410000000031214320114711013232 0ustar www-datawww-data#!/bin/sh PKG_NAME="ido" which gnome-autogen.sh || { echo "You need gnome-common from GNOME git" exit 1 } USE_GNOME2_MACROS=1 \ USE_COMMON_DOC_BUILD=yes \ gnome-autogen.sh --enable-gtk-doc $@./libido.pc.in0000644000004100000410000000036414320114711013433 0ustar www-datawww-dataprefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libido Description: Ayatana Indicator Display Objects Version: @VERSION@ Libs: -L${libdir} -lido-0.1 Cflags: -I${includedir}/libido-0.1 Requires: gtk+-2.0 ./ChangeLog0000644000004100000410000000000014320114711012775 0ustar www-datawww-data./Makefile.am.coverage0000644000004100000410000000250514320114711015065 0ustar www-datawww-data # Coverage targets .PHONY: clean-gcno clean-gcda \ coverage-html generate-coverage-html clean-coverage-html \ coverage-gcovr generate-coverage-gcovr clean-coverage-gcovr clean-local: clean-gcno clean-coverage-html clean-coverage-gcovr if HAVE_GCOV clean-gcno: @echo Removing old coverage instrumentation -find -name '*.gcno' -print | xargs -r rm clean-gcda: @echo Removing old coverage results -find -name '*.gcda' -print | xargs -r rm coverage-html: clean-gcda -$(MAKE) $(AM_MAKEFLAGS) -k check $(MAKE) $(AM_MAKEFLAGS) generate-coverage-html generate-coverage-html: @echo Collecting coverage data $(LCOV) --directory $(top_builddir) --capture --output-file coverage.info --no-checksum --compat-libtool LANG=C $(GENHTML) --prefix $(top_builddir) --output-directory coveragereport --title "Code Coverage" --legend --show-details coverage.info clean-coverage-html: clean-gcda -$(LCOV) --directory $(top_builddir) -z -rm -rf coverage.info coveragereport if HAVE_GCOVR coverage-gcovr: clean-gcda -$(MAKE) $(AM_MAKEFLAGS) -k check $(MAKE) $(AM_MAKEFLAGS) generate-coverage-gcovr generate-coverage-gcovr: @echo Generating coverage GCOVR report $(GCOVR) -x -r $(top_builddir) -o $(top_builddir)/coverage.xml clean-coverage-gcovr: clean-gcda -rm -rf $(top_builddir)/coverage.xml endif # HAVE_GCOVR endif # HAVE_GCOV ./tests/0000755000004100000410000000000014320114711012377 5ustar www-datawww-data./tests/gtest-menuitems.cpp0000644000004100000410000000451614320114711016243 0ustar www-datawww-data #include #include #include "idocalendarmenuitem.h" #include "idoentrymenuitem.h" #include "idoscalemenuitem.h" class TestMenuitems : public ::testing::Test { public: TestMenuitems() { gint argc = 0; gchar * argv[] = {NULL}; gtk_init(&argc, (gchar ***)&argv); return; } }; TEST_F(TestMenuitems, BuildCalendar) { GtkWidget * cal = ido_calendar_menu_item_new(); EXPECT_TRUE(cal != NULL); EXPECT_TRUE(IDO_IS_CALENDAR_MENU_ITEM(cal)); EXPECT_TRUE(GTK_IS_MENU_ITEM(cal)); GtkWidget * menu = gtk_menu_new(); gtk_widget_show(menu); gtk_menu_shell_append(GTK_MENU_SHELL(menu), cal); gtk_widget_show(cal); gtk_widget_realize(cal); EXPECT_TRUE(gtk_widget_get_realized(cal)); g_object_ref_sink(menu); g_object_unref(menu); return; } TEST_F(TestMenuitems, BuildEntry) { GtkWidget * entry = ido_entry_menu_item_new(); EXPECT_TRUE(entry != NULL); EXPECT_TRUE(IDO_IS_ENTRY_MENU_ITEM(entry)); EXPECT_TRUE(GTK_IS_MENU_ITEM(entry)); GtkWidget * menu = gtk_menu_new(); gtk_widget_show(menu); gtk_menu_shell_append(GTK_MENU_SHELL(menu), entry); gtk_widget_show(entry); gtk_widget_realize(entry); EXPECT_TRUE(gtk_widget_get_realized(entry)); g_object_ref_sink(menu); g_object_unref(menu); return; } TEST_F(TestMenuitems, BuildScaleDefault) { GtkWidget * scale = ido_scale_menu_item_new("Label", IDO_RANGE_STYLE_DEFAULT, gtk_adjustment_new(0.5, 0.0, 1.0, 0.01, 0.1, 0.1)); EXPECT_TRUE(scale != NULL); EXPECT_TRUE(IDO_IS_SCALE_MENU_ITEM(scale)); EXPECT_TRUE(GTK_IS_MENU_ITEM(scale)); GtkWidget * menu = gtk_menu_new(); gtk_widget_show(menu); gtk_menu_shell_append(GTK_MENU_SHELL(menu), scale); gtk_widget_show(scale); gtk_widget_realize(scale); EXPECT_TRUE(gtk_widget_get_realized(scale)); g_object_ref_sink(menu); g_object_unref(menu); return; } TEST_F(TestMenuitems, BuildScaleSmall) { GtkWidget * scale = ido_scale_menu_item_new("Label", IDO_RANGE_STYLE_SMALL, gtk_adjustment_new(0.5, 0.0, 1.0, 0.01, 0.1, 0.1)); EXPECT_TRUE(scale != NULL); EXPECT_TRUE(IDO_IS_SCALE_MENU_ITEM(scale)); EXPECT_TRUE(GTK_IS_MENU_ITEM(scale)); GtkWidget * menu = gtk_menu_new(); gtk_widget_show(menu); gtk_menu_shell_append(GTK_MENU_SHELL(menu), scale); gtk_widget_show(scale); gtk_widget_realize(scale); EXPECT_TRUE(gtk_widget_get_realized(scale)); g_object_ref_sink(menu); g_object_unref(menu); return; } ./tests/Makefile.am0000644000004100000410000000217114320114711014434 0ustar www-datawww-dataVER=3 IDOLIB = $(top_builddir)/src/libido3-0.1.la # xorg-gtest isn't buildable https://bugs.launchpad.net/ubuntu/+source/xorg-gtest/+bug/1388892 # check_LIBRARIES = libgtest.a check_PROGRAMS = TESTS = AM_CPPFLAGS = \ $(GTEST_CPPFLAGS) \ -I${top_srcdir}/src ############################# # Google Test base library ############################# nodist_libgtest_a_SOURCES = \ $(XORG_GTEST_SOURCE)/src/xorg-gtest-all.cpp \ $(GTEST_SOURCE)/gtest-all.cc \ $(XORG_GTEST_SOURCE)/src/xorg-gtest_main.cpp libgtest_a_CPPFLAGS = \ $(XORG_GTEST_CPPFLAGS) \ $(AM_CPPFLAGS) \ $(GTEST_CPPFLAGS) -w libgtest_a_CXXFLAGS = \ $(AM_CXXFLAGS) ############################# # Menuitem tests ############################# # xorg-gtest isn't buildable https://bugs.launchpad.net/ubuntu/+source/xorg-gtest/+bug/1388892 # TESTS += gtest-menuitems # check_PROGRAMS += gtest-menuitems gtest_menuitems_SOURCES = \ gtest-menuitems.cpp gtest_menuitems_CPPFLAGS = \ $(GCC_CFLAGS) \ $(GTK_CFLAGS) \ $(MAINTAINER_CFLAGS) \ $(AM_CPPFLAGS) gtest_menuitems_LDFLAGS = \ -pthread gtest_menuitems_LDADD = \ $(GTK_LIBS) \ $(IDOLIB) \ libgtest.a \ -lX11 -lXi ./COPYING.LGPL.2.10000644000004100000410000006363714320114711013343 0ustar www-datawww-data GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! ./TODO0000644000004100000410000000000014320114711011713 0ustar www-datawww-data./libido3.pc.in0000644000004100000410000000036614320114711013520 0ustar www-datawww-dataprefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libido Description: Ayatana Indicator Display Objects Version: @VERSION@ Libs: -L${libdir} -lido3-0.1 Cflags: -I${includedir}/libido3-0.1 Requires: gtk+-3.0 ./Makefile.am0000644000004100000410000000073614320114711013277 0ustar www-datawww-dataACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} VER=3 V = @ Q = $(V:1=) QUIET_GEN = $(Q:@=@echo ' GEN '$@;) SUBDIRS = src example tests %-0.1.pc: %.pc $(QUIET_GEN) cp -f $< $@ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libido$(VER)-0.1.pc CLEANFILES = libido-0.1.pc libido3-0.1.pc DISTCLEANFILES = libido.pc libido3.pc EXTRA_DIST = libido.pc.in libido3.pc.in DISTCHECK_CONFIGURE_FLAGS = --disable-gtk-doc include $(top_srcdir)/Makefile.am.coverage ./m4/0000755000004100000410000000000014320114711011555 5ustar www-datawww-data./m4/gcov.m40000644000004100000410000000471714320114711012766 0ustar www-datawww-data# Checks for existence of coverage tools: # * gcov # * lcov # * genhtml # * gcovr # # Sets ac_cv_check_gcov to yes if tooling is present # and reports the executables to the variables LCOV, GCOVR and GENHTML. AC_DEFUN([AC_TDD_GCOV], [ AC_ARG_ENABLE(gcov, AS_HELP_STRING([--enable-gcov], [enable coverage testing with gcov]), [use_gcov=$enableval], [use_gcov=no]) if test "x$use_gcov" = "xyes"; then # we need gcc: if test "$GCC" != "yes"; then AC_MSG_ERROR([GCC is required for --enable-gcov]) fi # Check if ccache is being used AC_CHECK_PROG(SHTOOL, shtool, shtool) case `$SHTOOL path $CC` in *ccache*[)] gcc_ccache=yes;; *[)] gcc_ccache=no;; esac if test "$gcc_ccache" = "yes" && (test -z "$CCACHE_DISABLE" || test "$CCACHE_DISABLE" != "1"); then AC_MSG_ERROR([ccache must be disabled when --enable-gcov option is used. You can disable ccache by setting environment variable CCACHE_DISABLE=1.]) fi lcov_version_list="1.6 1.7 1.8 1.9 1.10 1.11" AC_CHECK_PROG(LCOV, lcov, lcov) AC_CHECK_PROG(GENHTML, genhtml, genhtml) if test "$LCOV"; then AC_CACHE_CHECK([for lcov version], glib_cv_lcov_version, [ glib_cv_lcov_version=invalid lcov_version=`$LCOV -v 2>/dev/null | $SED -e 's/^.* //'` for lcov_check_version in $lcov_version_list; do if test "$lcov_version" = "$lcov_check_version"; then glib_cv_lcov_version="$lcov_check_version (ok)" fi done ]) else lcov_msg="To enable code coverage reporting you must have one of the following lcov versions installed: $lcov_version_list" AC_MSG_ERROR([$lcov_msg]) fi case $glib_cv_lcov_version in ""|invalid[)] lcov_msg="You must have one of the following versions of lcov: $lcov_version_list (found: $lcov_version)." AC_MSG_ERROR([$lcov_msg]) LCOV="exit 0;" ;; esac if test -z "$GENHTML"; then AC_MSG_ERROR([Could not find genhtml from the lcov package]) fi ac_cv_check_gcov=yes ac_cv_check_lcov=yes # Remove all optimization flags from CFLAGS changequote({,}) CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9]*//g'` changequote([,]) # Add the special gcc flags COVERAGE_CFLAGS="-O0 -fprofile-arcs -ftest-coverage" COVERAGE_CXXFLAGS="-O0 -fprofile-arcs -ftest-coverage" COVERAGE_LDFLAGS="-lgcov" # Check availability of gcovr AC_CHECK_PROG(GCOVR, gcovr, gcovr) if test -z "$GCOVR"; then ac_cv_check_gcovr=no else ac_cv_check_gcovr=yes fi fi ]) # AC_TDD_GCOV ./AUTHORS0000644000004100000410000000004714320114711012306 0ustar www-datawww-dataCody Russell