Compare commits

...

33 Commits

Author SHA1 Message Date
Owen W. Taylor
4f070317d2 lookingGlass: Get font from GConf
Instead of using "Monospace", pick the users configured monospace font
name up from GConf. (This is a nice touch, but is more done here to
demonstrate that we can do it rather than for any great utility.)
2009-09-21 20:13:00 -04:00
Owen W. Taylor
661100abe8 Port LookingGlass console to NBTK
* Style aspects like colors and fonts are moved into gnome-shell.css.
* Scrolling is adding using NbtkScrollView.

Based on a patch from Colin Walters
https://bugzilla.gnome.org/show_bug.cgi?id=591245
2009-09-21 20:11:09 -04:00
Owen W. Taylor
3e90b11cfb Add clutter-text properties to NbtkEntry and NbtkLabel
Add clutter-text properties to allow getting access to the underlying
ClutterText actor. This corresponds to the get_clutter_text() methods.

The PROP_LABEL and PROP_ENTRY enum values are renamed to PROP_TEXT to
match the names of the properties that they correspond to, and the
properties of NbtkEntry are reordered into alphabetical order.

Based on a patch from Colin Walters
https://bugzilla.gnome.org/show_bug.cgi?id=591245
http://bugzilla.moblin.org/show_bug.cgi?id=6313
2009-09-21 19:32:38 -04:00
Owen W. Taylor
4b4a1be420 Fix interaction of borders/background and scrolling
NbtkBoxLayout: Make consistent that the area scrolled and clipped
to is the content area (excluding borders and padding.) Translate
back appropriately when chaining up so that the parent background
is drawn at the right place and picking on the box (if it's reactive)
picks at the right place on the screen.

clip-to-allocation is removed from NbtkScrollView since it's just
not right - if the child has any non-moving elements, like headers or
borders, it will need to set a narrower clip. And even if the entire
child scrolls, we want to clip to an arrow that excludes the scrollbars.
2009-09-21 19:32:38 -04:00
Owen W. Taylor
1a4861ec4f Remove NbtkViewport from our tree
NbtkBoxLayout provides the basic functionality of 2-dimensional
scrolling and we don't use NbtkViewport anywhere, so remove it.

This avoids fixing NbtkViewport up for the interaction of scrolling
and borders/padding, which would be a little involved and require
a test program for NbtkViewport to be written.
2009-09-21 19:32:33 -04:00
Owen W. Taylor
2ac82da232 Allocate children as wide as the scrolled area
When we are scrolling a vertical box horizontally , children should be
allocated horizontally as wide as the full horizontal scrolled area,
not just to the size of the "viewport". Similarly for a horizontal box.

http://bugzilla.moblin.org/show_bug.cgi?id=6312
2009-09-21 19:32:33 -04:00
Owen W. Taylor
8f7e6f8117 Allow NbtkBoxLayout to shrink down to its minimum size
When a NbtkBoxLayout is allocated a size less than its natural size,
think "shrink" needs to be divided among the children that have
a smaller minimum size than natural size.

This is done by preferentially shrinking the children that are most
expanded from their minimum size and then increasing that set of
children until we've found enough total shrink.

A new method is used of allocating children at integral sizes - instead
of rounding the per-child extra amount to an integer (which causes
cumulative round-off errors), compute the position as we go along in
floats and round individually for each child widget.

Extend the box-layout test to include of a test of a box being set
to various widths, starting quite narrow.

http://bugzilla.moblin.org/show_bug.cgi?id=6311
2009-09-21 19:32:33 -04:00
Owen W. Taylor
d2b98701be Don't count not-visible children among expand children
When counting how many children we should divide extra space among,
don't count not-visible children.

http://bugzilla.moblin.org/show_bug.cgi?id=6310
2009-09-21 19:32:33 -04:00
Owen W. Taylor
faeda5dc8b Don't use the default stage when setting up adjustments
If the actor isn't in a stage, then setting up the adjustment
based on the actor's size (which we can't compute) and the
size of the default stage (which isn't relevant), doesn't make
sense. Just use arbitrary default values.

The adjustments will be updated to reasonable values when first
the box is first allocated.

It's not entirely clear to me why we ever want to compute the
adjustment settings this way; perhaps we should always use
default values.

http://bugzilla.moblin.org/show_bug.cgi?id=6307
2009-09-21 19:32:32 -04:00
Owen W. Taylor
70cb8e180b Match CSS for background extents
The CSS specification says that the background extends to the
edge of the border (settable in CSS3 with border-clip), make
BigRectangle match this by computing an "effective border color"
as 'border OVER background'.

(If we don't want this behavior - e.g., to be able to use the
transparent borders as margins, then alternatively transparent
border handling would have to be fixed in nbtk-widget.c, since
prior to this transparent and translucent borders were handled
differently.)
2009-09-21 19:32:32 -04:00
Owen W. Taylor
2232a92ba8 Rename ShellThemeImage to ShellBorderImage
The current CSS3 border-image is close to a superset of what we were
doing for -hippo-background-image. Woot! rename ShellThemeImage to
ShellBorderImage and change parsing to look for:

 border-image: <url> <number>...

Rather than

 -shell-background-image: <url> <length>...

percentanges for the border sizes are not currently supported, neither
are the keywords for handling of the middle part. We always do 'stretch'
for now.
2009-09-21 19:32:32 -04:00
Owen W. Taylor
4743a8e750 Add support for colored borders
Use BigRectangle to draw the border and background if there's
a border width or border radius and no border image. (Only
uniform borders are supported for now with some deviations
from the CSS model noted in the comments.)

The background color and image parameters are removed from
NbtkWidget's draw_background() method since they were not used
for NbtkButton (the only current user) and the encapsulation
break that they presented caused some minor problems.

Add a test case for borders, and also use borders to style
the buttons in the 'inline-style' test case.
2009-09-21 19:32:32 -04:00
Owen W. Taylor
e1390c7dd5 Centralize computations of border and padding into ShellThemeNode
Rather than repeating the computation of borders in many different
widget subclasses, add helper functions:

 shell_theme_node_adjust_for_height()
 shell_theme_node_adjust_preferred_width()
 shell_theme_node_adjust_for_width()
 shell_theme_node_adjust_preferred_height()
 shell_theme_node_get_content_box()

That are used in get_preferred_width()/get_preferred_height() and
allocate() methods to consistently apply the necessary adjustments.
This allows removing the NbtkPadding type.

Queueing a relayout when the borders/padding change is moved from
nbtk_widget_real_style_changed() to the invoking code to allow access
to the old ShellThemeNode for comparison. (Should this be added as
a parameter to the signal?)

Borders are included in the geometry adjustments, but borders
are not yet drawn.
2009-09-21 19:32:24 -04:00
Owen W. Taylor
49ba54820c ShellThemeNode: Add border-radius support
Add support for parsing and caching the border-radius property.
Different radii for the 4 corners are supported; elliptical corners
are not supported.
2009-09-21 19:32:23 -04:00
Owen W. Taylor
8ffa161a7f Fix problems with 4-sided padding: specifiers
The test for identifying such a specifier was wrong, and the last
value was assigned to the wrong sides.
2009-09-21 19:32:23 -04:00
Owen W. Taylor
0eca3efcb0 Add support for inline styles
Add support for passing an inline-style string when creating a
ShellThemeNode.

Hook this up to a new 'style' property of NbtkWidget.

Add a test case that demonstrates using this to update font sizes
on the fly.
2009-09-21 19:32:23 -04:00
Owen W. Taylor
9c3af62dc4 run-test.sh: support running tests under gdb
As with the 'gnome-shell' -g/--debug can be passed to run under
the debugger.
2009-09-21 19:32:23 -04:00
Owen W. Taylor
db0c2b5959 Port our imported parts of Nbtk to ShellTheme
ShellTheme replaces both NbtkStyle and ccss_stylesheet_t.

The interface NbtkStylable is replaced by usage of ShellThemeNode.
A concrete node class allows some significant optimizations of property
inheritance that would have been much more difficult to achieve with
the highly abstract pair of NbtkStylable and ccss_node_t.

Some operations that were previously on NbtkStylable (like the
::style-changed signal) are directly on NtkWidget.

Custom properties are no longer registered as param-specs; instead you
call directly into shell theme node to look up a length or color:

shell_theme_node_get_length (theme_node, "border-spacing", FALSE, &spacing);

The dependency on libccss is dropped, while preserving all existing
functionality and adding proper parsing and inheritance of font properties
and proper inheritance for the 'color' property.

Some more javascript tests for CSS functionality are added; workarounds for
a CSS bug where *.some-class was needed instead of .some-class are removed.
2009-09-21 19:32:18 -04:00
Owen W. Taylor
98215f497d Import stylesheet code from hippo-canvas
Import:

  HippoCanvasTheme      => ShellTheme
  HippoCanvasThemeImage => ShellThemeImage
  HippoCanvasStyle      => ShellThemeNode

ShellThemeContext is a new class managing the theme for a stage and
global properties like resolution.

test-theme.c is a newly written test program to do verification of the
style matching and property handling rules.

Various changes are made in the import:

 - Comprehensive reindentation
 - guint32 pixels replaced with ClutterColor
 - General pseudo-class support added
 - Old-fashioned (non-bordered) background image support added, though
   with no support for repeat, etc.
 - Bug fixes for problems revealed by test program
2009-09-20 16:59:06 -04:00
Owen W. Taylor
9dbafe156e Makefile.am cleanups for NBTK
Clean up indentation, line up backslashes, and add missing $(AM_V_GEN).
Remove include of GTK+ when generating Nbtk-1.0.gir.
2009-09-20 16:58:30 -04:00
Owen W. Taylor
277dd7106a Fix installation and distribution of stylesheet data
Install and distribute gnome-shell.css and theme images. They are moved
down from $datadir to $datadir/theme to avoid a weirdness where we have
images in $datadir and then also in $datadir/images.

(Also moved in the source tree to avoid adding another difference between
installed and uninstalled operation.)
2009-09-18 16:29:28 -04:00
Owen W. Taylor
431f299756 Extend distcheck for files in Git to all files
Instead of just checking that we distribute all Javascript files, check
that we distribute everything that is in Git.

The toplevel Makefile.am has a variable DIST_EXCLUDE that lists patterns
of files that we actually don't want to distribute.

Remove several stale C files that we are no longer using.
2009-09-18 16:18:54 -04:00
Owen W. Taylor
d8d7f5f711 Add some structure for interactive tests of UI components
js/ui/environment.js: Split out initial UI setup (Tweener initialization,
  Nbtk monkey-patching) into a separate file we can import from tests.

tests/: Directory for various types of tests
tests/run-test.sh: Shell script that to run tests with an appropriate
  environment set up.

tests/testcommon/: Common modules and data for tests
tests/interactive/: Interactive tests

tests/interactive/box-layout.js: A sample test of NbtkLayout
2009-09-18 16:18:50 -04:00
Owen W. Taylor
a07af9fb14 Monkey-patch in ClutterContainer methods for NbtkBoxLayout
Setting options for children added to NbtkBoxLayout is not convenient
since we are missing the varargs methods of clutter_container.

Patch in:

 child_set() - set properties of a child
 add() - add a child and set properties (this is different from
         clutter_container_add()! I think the deviation is
         with avoiding the awkward name add_with_properties()
         which is what might be expected. ClutterContainer
         currently doesn't have a method like this at all.)

The code is written to allow patching into multiple ClutterContainer
classes but for now only NbtkBoxLayout is patched, since it's the only
container we are using where we need to set options as properties.

https://bugzilla.gnome.org/show_bug.cgi?id=595419
2009-09-16 19:59:38 -04:00
Owen W. Taylor
f1f11f1e76 Add GObject Introspection annotations
Add GObject Introspection annotations to methods where needed, in
particular adding (transfer none) to return values that don't transfer
ownership.

clutter_texture_cache_get_actor() and clutter_texture_cache_get_texture()
are annotated as (transfer none) since they return a newly
created *floating* texture.

https://bugzilla.gnome.org/show_bug.cgi?id=591245
2009-09-16 19:12:53 -04:00
Colin Walters
c60a6a49de Import NbtkEntry, NbtkLabel, NbtkClipboard
For now this commit introduces an external dependency on clutter-imcontext.

https://bugzilla.gnome.org/show_bug.cgi?id=591245
2009-09-16 18:04:51 -04:00
Colin Walters
6687054474 Import NbtkBoxLayout, NbtkBoxLayoutChild
https://bugzilla.gnome.org/show_bug.cgi?id=591245
2009-09-16 17:59:06 -04:00
Colin Walters
60819b3a79 Add css for scrolling
Port bits of Nbtk's default.css into gnome-shell.css, and use some
hand-rolled .pngs with colors from
http://live.gnome.org/GnomeShell/DesignerPlayground/ExpandedViewMockups

https://bugzilla.gnome.org/show_bug.cgi?id=591245
2009-09-16 17:58:55 -04:00
Colin Walters
3e265b4bc6 Load gnome-shell.css at startup
https://bugzilla.gnome.org/show_bug.cgi?id=591245
2009-09-16 17:56:24 -04:00
Colin Walters
e2aa2a00f0 Add a "datadir" property
Will be used to load stylesheets from main.js.

https://bugzilla.gnome.org/show_bug.cgi?id=591245
2009-09-16 17:56:24 -04:00
Colin Walters
1edc88a2bd Remove hardcoded '28' from NbtkScrollView
https://bugzilla.gnome.org/show_bug.cgi?id=591245
2009-09-16 17:56:22 -04:00
Colin Walters
271e4ca07e Import NbtkScrollView and dependencies
https://bugzilla.gnome.org/show_bug.cgi?id=591245
2009-09-16 16:52:26 -04:00
Colin Walters
9f79296276 Import nbtk core
Import the core NbtkWidget/NbtkBin and their dependencies.

https://bugzilla.gnome.org/show_bug.cgi?id=591245
2009-09-16 11:35:43 -04:00
82 changed files with 17851 additions and 491 deletions

2
.gitignore vendored
View File

@ -38,5 +38,7 @@ src/gnomeshell-taskpanel
src/gnome-shell
src/test-recorder
src/test-recorder.ogg
src/test-theme
stamp-h1
tests/run-test.sh
xmldocs.make

View File

@ -1,13 +1,22 @@
SUBDIRS = data js src po
SUBDIRS = data js src tests po
EXTRA_DIST = \
.project \
.settings
.settings \
autogen.sh
# These are files checked into Git that we don't want to distribute
DIST_EXCLUDE = \
.gitignore \
gnome-shell.doap \
MAINTAINERS \
tools/build/*
distcheck-hook:
@echo "Checking disted javascript against files in git"
@echo "Checking disted files against files in git"
@failed=false; \
for f in `cd $(srcdir) && git ls-files js` ; do \
exclude=`(for p in $(DIST_EXCLUDE) ; do echo --exclude=$$p ; done)`; \
for f in `cd $(srcdir) && git ls-files $$exclude` ; do \
if ! test -e $(distdir)/$$f ; then \
echo File missing from distribution: $$f ; \
failed=true ; \

View File

@ -57,8 +57,10 @@ PKG_CHECK_MODULES(MUTTER_PLUGIN, gio-unix-2.0 gtk+-2.0 dbus-glib-1 mutter-plugin
gnome-desktop-2.0 >= 2.26 libstartup-notification-1.0
gobject-introspection-1.0 >= 0.6.5)
PKG_CHECK_MODULES(TIDY, clutter-1.0)
PKG_CHECK_MODULES(NBTK, clutter-1.0 gtk+-2.0 clutter-imcontext-0.1)
PKG_CHECK_MODULES(BIG, clutter-1.0 gtk+-2.0 librsvg-2.0)
PKG_CHECK_MODULES(GDMUSER, dbus-glib-1 gtk+-2.0)
PKG_CHECK_MODULES(TOOLKIT, clutter-1.0 libcroco-0.6)
PKG_CHECK_MODULES(TRAY, gtk+-2.0)
MUTTER_BIN_DIR=`$PKG_CONFIG --variable=exec_prefix mutter-plugins`/bin
@ -128,5 +130,6 @@ AC_OUTPUT([
js/misc/Makefile
js/ui/Makefile
src/Makefile
tests/Makefile
po/Makefile.in
])

View File

@ -12,18 +12,26 @@ gnome-shell.desktop.in: gnome-shell.desktop.in.in
gnome-shell.desktop: gnome-shell.desktop.in
$(AM_V_GEN) sed s/^_// < $< > $@ || rm $@
imagedir = $(pkgdatadir)/images
dist_image_DATA = \
add-workspace.svg \
app-well-glow.png \
back.svg \
close.svg \
close-black.svg \
info.svg \
magnifier.svg \
imagesdir = $(pkgdatadir)/images
dist_images_DATA = \
add-workspace.svg \
app-well-glow.png \
back.svg \
close.svg \
close-black.svg \
info.svg \
magnifier.svg \
remove-workspace.svg
themedir = $(pkgdatadir)/theme
dist_theme_DATA = \
theme/gnome-shell.css \
theme/scroll-button-down.png \
theme/scroll-button-down-hover.png \
theme/scroll-button-up.png \
theme/scroll-button-up-hover.png \
theme/scroll-vhandle.png
schemadir = @GCONF_SCHEMA_FILE_DIR@
schema_DATA = gnome-shell.schemas

View File

@ -0,0 +1,97 @@
/* Copyright 2009, Red Hat, Inc.
*
* Portions adapted from NBTK's data/style/default.css
* Copyright 2009 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
NbtkScrollBar
{
background-color: #354761;
padding: 0px;
}
NbtkScrollView
{
scrollbar-width: 16px;
scrollbar-height: 16px;
}
NbtkButton#up-stepper
{
border-image: url("scroll-button-up.png") 5;
}
NbtkButton#up-stepper:hover,
NbtkButton#up-stepper:active
{
border-image: url("scroll-button-up-hover.png") 5;
}
NbtkButton#down-stepper
{
border-image: url("scroll-button-down.png") 5;
}
NbtkButton#down-stepper:hover,
NbtkButton#down-stepper:active
{
border-image: url("scroll-button-down-hover.png") 5;
}
NbtkScrollBar NbtkButton#vhandle
{
border-image: url("scroll-vhandle.png") 5;
}
NbtkScrollBar NbtkButton#vhandle:hover
{
border-image: url("scroll-vhandle.png") 5;
}
/* LookingGlass */
#LookingGlassDialog
{
background-color: rgba(0,0,0,0.85);
spacing: 4px;
padding: 4px;
border: 1px solid rgba(0,0,172,0.85);
border-radius: 4px;
color: #88ff66;
}
#LookingGlassDialog > #Toolbar
{
border: 1px solid grey;
border-radius: 4px;
}
#LookingGlassDialog NbtkLabel
{
color: #88ff66;
}
#LookingGlassDialog NbtkEntry
{
color: #88ff66;
}
#LookingGlassDialog NbtkBoxLayout#EvalBox
{
padding: 4px;
spacing: 4px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

View File

@ -9,6 +9,7 @@ dist_jsui_DATA = \
dash.js \
dnd.js \
docDisplay.js \
environment.js \
genericDisplay.js \
link.js \
lookingGlass.js \

32
js/ui/environment.js Normal file
View File

@ -0,0 +1,32 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Nbtk = imports.gi.Nbtk;
const Tweener = imports.ui.tweener;
// "monkey patch" in some varargs ClutterContainer methods; we need
// to do this per-container class since there is no representation
// of interfaces in Javascript
function _patchContainerClass(containerClass) {
// This one is a straightforward mapping of the C method
containerClass.prototype.child_set = function(actor, props) {
let meta = this.get_child_meta(actor);
for (prop in props)
meta[prop] = props[prop];
};
// clutter_container_add() actually is a an add-many-actors
// method. We conveniently, but somewhat dubiously, take the
// this opportunity to make it do something more useful.
containerClass.prototype.add = function(actor, props) {
this.add_actor(actor);
if (props)
this.child_set(actor, props);
};
}
_patchContainerClass(Nbtk.BoxLayout);
function init() {
Tweener.init();
}

View File

@ -4,6 +4,7 @@ const Big = imports.gi.Big;
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const Pango = imports.gi.Pango;
const Nbtk = imports.gi.Nbtk;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const Lang = imports.lang;
@ -12,18 +13,7 @@ const Mainloop = imports.mainloop;
const Tweener = imports.ui.tweener;
const Main = imports.ui.main;
const LG_BORDER_COLOR = new Clutter.Color();
LG_BORDER_COLOR.from_pixel(0x0000aca0);
const LG_BACKGROUND_COLOR = new Clutter.Color();
LG_BACKGROUND_COLOR.from_pixel(0x000000d5);
const GREY = new Clutter.Color();
GREY.from_pixel(0xAFAFAFFF);
const MATRIX_GREEN = new Clutter.Color();
MATRIX_GREEN.from_pixel(0x88ff66ff);
// FIXME pull from GConf
const MATRIX_FONT = 'Monospace 10';
/* Imports...feel free to add here as needed */
/* Imports...feel free to add here as needed */
var commandHeader = "const Clutter = imports.gi.Clutter; " +
"const GLib = imports.gi.GLib; " +
"const Gtk = imports.gi.Gtk; " +
@ -47,7 +37,7 @@ function Notebook() {
Notebook.prototype = {
_init: function() {
this.actor = new Big.Box();
this.actor = new Nbtk.BoxLayout({ vertical: true });
this.tabControls = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
spacing: 4, padding: 2 });
@ -58,21 +48,24 @@ Notebook.prototype = {
appendPage: function(name, child) {
let labelOuterBox = new Big.Box({ padding: 2 });
let labelBox = new Big.Box({ padding: 2, border_color: MATRIX_GREEN,
reactive: true });
let labelBox = new Nbtk.BoxLayout({ reactive: true });
labelOuterBox.append(labelBox, Big.BoxPackFlags.NONE);
let label = new Clutter.Text({ color: MATRIX_GREEN,
font_name: MATRIX_FONT,
text: name });
let label = new Nbtk.Label({ text: name });
labelBox.connect('button-press-event', Lang.bind(this, function () {
this.selectChild(child);
return true;
}));
labelBox.append(label, Big.BoxPackFlags.EXPAND);
this._tabs.push([child, labelBox]);
child.hide();
this.actor.append(child, Big.BoxPackFlags.EXPAND);
labelBox.add(label, { expand: true });
this.tabControls.append(labelOuterBox, Big.BoxPackFlags.NONE);
let scrollview = new Nbtk.ScrollView({ x_fill: true, y_fill: true });
scrollview.get_hscroll_bar().hide();
scrollview.add_actor(child);
this._tabs.push([child, labelBox, scrollview]);
scrollview.hide();
this.actor.add(scrollview, { expand: true });
if (this._selectedIndex == -1)
this.selectIndex(0);
},
@ -80,10 +73,10 @@ Notebook.prototype = {
_unselect: function() {
if (this._selectedIndex < 0)
return;
let [child, labelBox] = this._tabs[this._selectedIndex];
let [child, labelBox, scrollview] = this._tabs[this._selectedIndex];
labelBox.padding = 2;
labelBox.border = 0;
child.hide();
scrollview.hide();
this._selectedIndex = -1;
},
@ -95,10 +88,10 @@ Notebook.prototype = {
this.emit('selection', null);
return;
}
let [child, labelBox] = this._tabs[index];
let [child, labelBox, scrollview] = this._tabs[index];
labelBox.padding = 1;
labelBox.border = 1;
child.show();
scrollview.show();
this._selectedIndex = index;
this.emit('selection', child);
},
@ -108,7 +101,7 @@ Notebook.prototype = {
this.selectIndex(-1);
else {
for (let i = 0; i < this._tabs.length; i++) {
let [tabChild, labelBox] = this._tabs[i];
let [tabChild, labelBox, scrollview] = this._tabs[i];
if (tabChild == child) {
this.selectIndex(i);
return;
@ -130,20 +123,19 @@ Result.prototype = {
this.actor = new Big.Box();
let cmdTxt = new Clutter.Text({ color: MATRIX_GREEN,
font_name: MATRIX_FONT,
ellipsize: Pango.EllipsizeMode.END,
text: command });
let cmdTxt = new Nbtk.Label({ text: command });
cmdTxt.ellipsize = Pango.EllipsizeMode.END;
this.actor.append(cmdTxt, Big.BoxPackFlags.NONE);
let resultTxt = new Clutter.Text({ color: MATRIX_GREEN,
font_name: MATRIX_FONT,
ellipsize: Pango.EllipsizeMode.END,
text: "r(" + index + ") = " + o });
let resultTxt = new Nbtk.Label({ text: "r(" + index + ") = " + o });
resultTxt.ellipsize = Pango.EllipsizeMode.END;
this.actor.append(resultTxt, Big.BoxPackFlags.NONE);
let line = new Big.Box({ border_color: GREY,
border_bottom: 1,
height: 8 });
this.actor.append(line, Big.BoxPackFlags.NONE);
let line = new Clutter.Rectangle({ name: "Separator",
height: 1 });
let padBin = new Nbtk.Bin({ name: "Separator", x_fill: true, y_fill: true });
padBin.add_actor(line);
this.actor.append(padBin, Big.BoxPackFlags.NONE);
}
}
@ -158,17 +150,14 @@ ActorHierarchy.prototype = {
this._parentList = [];
this.actor = new Big.Box({ spacing: 4,
border: 1,
padding: 4,
border_color: GREY });
this.actor = new Nbtk.BoxLayout({ name: "ActorHierarchy", vertical: true });
},
setTarget: function(actor) {
this._previousTarget = this._target;
this.target = actor;
this.actor.remove_all();
this.actor.get_children().forEach(function (child) { child.destroy(); });
if (!(actor instanceof Clutter.Actor))
return;
@ -181,11 +170,9 @@ ActorHierarchy.prototype = {
while ((parent = parent.get_parent()) != null) {
this._parentList.push(parent);
let link = new Clutter.Text({ color: MATRIX_GREEN,
font_name: MATRIX_FONT,
reactive: true,
text: "" + parent });
this.actor.append(link, Big.BoxPackFlags.IF_FITS);
let link = new Nbtk.Label({ reactive: true,
text: "" + parent });
this.actor.add_actor(link);
let parentTarget = parent;
link.connect('button-press-event', Lang.bind(this, function () {
this._selectByActor(parentTarget);
@ -214,16 +201,13 @@ PropertyInspector.prototype = {
this._parentList = [];
this.actor = new Big.Box({ spacing: 4,
border: 1,
padding: 4,
border_color: GREY });
this.actor = new Nbtk.BoxLayout({ name: "PropertyInspector", vertical: true });
},
setTarget: function(actor) {
this.target = actor;
this.actor.remove_all();
this.actor.get_children().forEach(function (child) { child.destroy(); });
for (let propName in actor) {
let valueStr;
@ -233,11 +217,9 @@ PropertyInspector.prototype = {
valueStr = '<error>';
}
let propText = propName + ": " + valueStr;
let propDisplay = new Clutter.Text({ color: MATRIX_GREEN,
font_name: MATRIX_FONT,
reactive: true,
text: propText });
this.actor.append(propDisplay, Big.BoxPackFlags.IF_FITS);
let propDisplay = new Nbtk.Label({ reactive: true,
text: propText });
this.actor.add_actor(propDisplay);
}
}
}
@ -249,20 +231,16 @@ function Inspector() {
Inspector.prototype = {
_init: function() {
let width = 150;
let eventHandler = new Big.Box({ background_color: LG_BACKGROUND_COLOR,
border: 1,
border_color: LG_BORDER_COLOR,
corner_radius: 4,
y: global.stage.height/2,
reactive: true
});
let eventHandler = new Nbtk.BoxLayout({ name: "LookingGlassDialog",
vertical: false,
y: Math.floor(global.stage.height/2),
reactive: true });
eventHandler.connect('notify::allocation', Lang.bind(this, function () {
eventHandler.x = Math.floor((global.stage.width)/2 - (eventHandler.width)/2);
}));
global.stage.add_actor(eventHandler);
let displayText = new Clutter.Text({ color: MATRIX_GREEN,
font_name: MATRIX_FONT, text: '' });
eventHandler.append(displayText, Big.BoxPackFlags.EXPAND);
let displayText = new Nbtk.Label();
eventHandler.add(displayText, { expand: true });
let borderPaintTarget = null;
let borderPaintId = null;
@ -321,29 +299,26 @@ LookingGlass.prototype = {
this._offset = 0;
this._results = [];
// TODO replace with scrolling or something better
this._maxItems = 10;
// Sort of magic, but...eh.
this._maxItems = 150;
this.actor = new Nbtk.BoxLayout({ name: "LookingGlassDialog",
vertical: true,
visible: false });
let gconf = Shell.GConf.get_default();
gconf.watch_directory("/desktop/gnome/interface");
gconf.connect("changed::/desktop/gnome/interface/monospace_font_name",
Lang.bind(this, this._updateFont));
this._updateFont();
this.actor = new Big.Box({ background_color: LG_BACKGROUND_COLOR,
border: 1,
border_color: LG_BORDER_COLOR,
corner_radius: 4,
padding_top: 8,
padding_left: 4,
padding_right: 4,
padding_bottom: 4,
spacing: 4,
visible: false
});
global.stage.add_actor(this.actor);
let toolbar = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
border: 1, border_color: GREY,
corner_radius: 4 });
this.actor.append(toolbar, Big.BoxPackFlags.NONE);
let toolbar = new Nbtk.BoxLayout({ name: "Toolbar" });
this.actor.add_actor(toolbar);
let inspectIcon = Shell.TextureCache.get_default().load_gicon(new Gio.ThemedIcon({ name: 'gtk-color-picker' }),
24);
toolbar.append(inspectIcon, Big.BoxPackFlags.NONE);
toolbar.add_actor(inspectIcon);
inspectIcon.reactive = true;
inspectIcon.connect('button-press-event', Lang.bind(this, function () {
let inspector = new Inspector();
@ -361,31 +336,26 @@ LookingGlass.prototype = {
}));
let notebook = new Notebook();
this.actor.append(notebook.actor, Big.BoxPackFlags.EXPAND);
toolbar.append(notebook.tabControls, Big.BoxPackFlags.END);
this.actor.add(notebook.actor, { expand: true });
this._evalBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
spacing: 4 });
let emptyBox = new Nbtk.Bin();
toolbar.add(emptyBox, { expand: true });
toolbar.add_actor(notebook.tabControls);
this._evalBox = new Nbtk.BoxLayout({ name: "EvalBox", vertical: true });
notebook.appendPage('Evaluator', this._evalBox);
this._resultsArea = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
spacing: 4 });
this._evalBox.append(this._resultsArea, Big.BoxPackFlags.EXPAND);
this._evalBox.add(this._resultsArea, { expand: true });
let entryArea = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL });
this._evalBox.append(entryArea, Big.BoxPackFlags.NONE);
this._evalBox.add_actor(entryArea);
let label = new Clutter.Text({ color: MATRIX_GREEN,
font_name: MATRIX_FONT,
text: 'js>>> ' });
let label = new Nbtk.Label({ text: 'js>>> ' });
entryArea.append(label, Big.BoxPackFlags.NONE);
this._entry = new Clutter.Text({ color: MATRIX_GREEN,
font_name: MATRIX_FONT,
editable: true,
activatable: true,
singleLineMode: true,
text: ''});
this._entry = new Nbtk.Entry();
/* unmapping the edit box will un-focus it, undo that */
notebook.connect('selection', Lang.bind(this, function (nb, child) {
if (child == this._evalBox)
@ -403,7 +373,7 @@ LookingGlass.prototype = {
notebook.selectIndex(0);
}));
this._entry.connect('activate', Lang.bind(this, function (o, e) {
this._entry.clutter_text.connect('activate', Lang.bind(this, function (o, e) {
let text = o.get_text();
// Ensure we don't get newlines in the command; the history file is
// newline-separated.
@ -416,7 +386,7 @@ LookingGlass.prototype = {
this._historyNavIndex = -1;
return true;
}));
this._entry.connect('key-press-event', Lang.bind(this, function(o, e) {
this._entry.clutter_text.connect('key-press-event', Lang.bind(this, function(o, e) {
let symbol = e.get_key_symbol();
if (symbol == Clutter.Escape) {
this.close();
@ -446,6 +416,19 @@ LookingGlass.prototype = {
}));
},
_updateFont: function() {
let gconf = Shell.GConf.get_default();
let fontName = gconf.get_string("/desktop/gnome/interface/monospace_font_name");
// This is mishandled by the scanner - should by Pango.FontDescription_from_string(fontName);
// https://bugzilla.gnome.org/show_bug.cgi?id=595889
let fontDesc = Pango.Font.description_from_string(fontName);
// We ignore everything but size and style; you'd be crazy to set your system-wide
// monospace font to be bold/oblique/etc. Could easily be added here.
this.actor.style =
'font-size: ' + fontDesc.get_size() / 1024. + (fontDesc.get_size_is_absolute() ? 'px' : 'pt') + ';'
+ 'font-family: "' + fontDesc.get_family() + '";';
},
_readHistory: function () {
if (!this._historyFile.query_exists(null))
return;

View File

@ -7,16 +7,17 @@ const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Nbtk = imports.gi.Nbtk;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const Chrome = imports.ui.chrome;
const Environment = imports.ui.environment;
const Overview = imports.ui.overview;
const Panel = imports.ui.panel;
const RunDialog = imports.ui.runDialog;
const LookingGlass = imports.ui.lookingGlass;
const Sidebar = imports.ui.sidebar;
const Tweener = imports.ui.tweener;
const WindowManager = imports.ui.windowManager;
const DEFAULT_BACKGROUND_COLOR = new Clutter.Color();
@ -43,7 +44,7 @@ function start() {
global.grab_dbus_service();
Tweener.init();
Environment.init();
// Ensure ShellAppMonitor is initialized; this will
// also initialize ShellAppSystem first. ShellAppSystem
@ -66,6 +67,11 @@ function start() {
for (let i = 0; i < children.length; i++)
children[i].destroy();
let themeContext = Shell.ThemeContext.get_for_stage (global.stage);
let stylesheetPath = global.datadir + "/theme/gnome-shell.css";
let theme = new Shell.Theme ({ application_stylesheet: stylesheetPath });
themeContext.set_theme (theme);
global.connect('panel-run-dialog', function(panel) {
// Make sure not more than one run dialog is shown.
getRunDialog().open();

117
src/Makefile-nbtk.am Normal file
View File

@ -0,0 +1,117 @@
nbtk_cflags = \
-I$(top_srcdir)/src \
-DPREFIX=\""$(prefix)"\" \
-DLIBDIR=\""$(libdir)"\" \
-DG_DISABLE_DEPRECATED \
-DG_LOG_DOMAIN=\"Nbtk\" \
-DNBTK_COMPILATION \
$(NBTK_CFLAGS) \
$(NULL)
nbtk_built_sources = \
nbtk-enum-types.h \
nbtk-enum-types.c \
nbtk-marshal.h \
nbtk-marshal.c
BUILT_SOURCES += $(nbtk_built_sources)
EXTRA_DIST += \
nbtk/nbtk-marshal.list \
nbtk/nbtk-enum-types.h.in \
nbtk/nbtk-enum-types.c.in
CLEANFILES += stamp-nbtk-marshal.h stamp-nbtk-enum-types.h
nbtk-marshal.h: stamp-nbtk-marshal.h
@true
stamp-nbtk-marshal.h: Makefile nbtk/nbtk-marshal.list
$(AM_V_GEN) $(GLIB_GENMARSHAL) \
--prefix=_nbtk_marshal \
--header \
$(srcdir)/nbtk/nbtk-marshal.list > $@.tmp && \
(cmp -s $@.tmp nbtk-marshal.h || cp -f $@.tmp nbtk-marshal.h) && \
rm -f $@.tmp && \
echo timestamp > $(@F)
nbtk-marshal.c: Makefile nbtk/nbtk-marshal.list
$(AM_V_GEN) (echo "#include \"nbtk-marshal.h\"" ; \
$(GLIB_GENMARSHAL) \
--prefix=_nbtk_marshal \
--body \
$(srcdir)/nbtk/nbtk-marshal.list ) > $@.tmp && \
cp -f $@.tmp nbtk-marshal.c && \
rm -f $@.tmp
nbtk-enum-types.h: stamp-nbtk-enum-types.h Makefile
@true
stamp-nbtk-enum-types.h: $(source_h) nbtk/nbtk-enum-types.h.in
$(AM_V_GEN) ( cd $(srcdir) && \
$(GLIB_MKENUMS) \
--template nbtk/nbtk-enum-types.h.in \
$(nbtk_source_h) ) >> $@.tmp && \
(cmp -s $@.tmp nbtk-enum-types.h || cp $@.tmp nbtk-enum-types.h) && \
rm -f $@.tmp && \
echo timestamp > $(@F)
nbtk-enum-types.c: stamp-nbtk-enum-types.h nbtk/nbtk-enum-types.c.in
$(AM_V_GEN) ( cd $(srcdir) && \
$(GLIB_MKENUMS) \
--template nbtk/nbtk-enum-types.c.in \
$(nbtk_source_h) ) >> $@.tmp && \
cp $@.tmp $@ && \
rm -f $@.tmp
# please, keep this sorted alphabetically
nbtk_source_h = \
nbtk/nbtk-adjustment.h \
nbtk/nbtk-bin.h \
nbtk/nbtk-box-layout.h \
nbtk/nbtk-box-layout-child.h \
nbtk/nbtk-button.h \
nbtk/nbtk-clipboard.h \
nbtk/nbtk-entry.h \
nbtk/nbtk-label.h \
nbtk/nbtk-private.h \
nbtk/nbtk-scrollable.h \
nbtk/nbtk-scroll-bar.h \
nbtk/nbtk-scroll-view.h \
nbtk/nbtk-subtexture.h \
nbtk/nbtk-texture-cache.h \
nbtk/nbtk-texture-frame.h \
nbtk/nbtk-tooltip.h \
nbtk/nbtk-types.h \
nbtk/nbtk-widget.h \
$(NULL)
# please, keep this sorted alphabetically
nbtk_source_c = \
nbtk/nbtk-adjustment.c \
nbtk/nbtk-bin.c \
nbtk/nbtk-box-layout.c \
nbtk/nbtk-box-layout-child.c \
nbtk/nbtk-button.c \
nbtk/nbtk-clipboard.c \
nbtk/nbtk-entry.c \
nbtk/nbtk-label.c \
nbtk/nbtk-private.c \
nbtk/nbtk-scrollable.c \
nbtk/nbtk-scroll-bar.c \
nbtk/nbtk-scroll-view.c \
nbtk/nbtk-subtexture.c \
nbtk/nbtk-texture-cache.c \
nbtk/nbtk-texture-frame.c \
nbtk/nbtk-tooltip.c \
nbtk/nbtk-widget.c \
$(NULL)
noinst_LTLIBRARIES += libnbtk-1.0.la
libnbtk_1_0_la_LIBADD = $(NBTK_LIBS)
libnbtk_1_0_la_SOURCES = \
$(nbtk_source_c) \
$(nbtk_source_h) \
$(nbtk_built_sources) \
$(NULL)
libnbtk_1_0_la_CPPFLAGS = $(nbtk_cflags)
libnbtk_1_0_la_LDFLAGS = $(LDADD)

36
src/Makefile-toolkit.am Normal file
View File

@ -0,0 +1,36 @@
toolkit_cflags = \
-I$(top_srcdir)/src \
-DPREFIX=\""$(prefix)"\" \
-DLIBDIR=\""$(libdir)"\" \
-DG_DISABLE_DEPRECATED \
-DG_LOG_DOMAIN=\"Shell\" \
$(TOOLKIT_CFLAGS)
# please, keep this sorted alphabetically
toolkit_sources = \
toolkit/shell-border-image.c \
toolkit/shell-border-image.h \
toolkit/shell-theme.c \
toolkit/shell-theme.h \
toolkit/shell-theme-context.c \
toolkit/shell-theme-context.h \
toolkit/shell-theme-node.c \
toolkit/shell-theme-node.h \
toolkit/shell-theme-private.h
non_gir_toolkit_sources = \
toolkit/shell-theme-private.h
noinst_LTLIBRARIES += libshell-toolkit.la
libshell_toolkit_la_LIBADD = $(TOOLKIT_LIBS)
libshell_toolkit_la_SOURCES = $(toolkit_sources) $(toolkit_built_sources)
libshell_toolkit_la_CPPFLAGS = $(toolkit_cflags)
libshell_toolkit_la_LDFLAGS = $(LDADD)
noinst_PROGRAMS += test-theme
test_theme_CPPFLAGS = $(toolkit_cflags)
test_theme_LDADD = libshell-toolkit.la
test_theme_SOURCES = toolkit/test-theme.c

View File

@ -4,6 +4,7 @@ CLEANFILES =
EXTRA_DIST =
libexec_PROGRAMS =
noinst_LTLIBRARIES =
noinst_PROGRAMS =
.AUTOPARALLEL:
@ -24,6 +25,8 @@ EXTRA_DIST += gnome-shell.in
include Makefile-big.am
include Makefile-gdmuser.am
include Makefile-nbtk.am
include Makefile-toolkit.am
include Makefile-tray.am
gnome_shell_cflags = \
@ -96,7 +99,7 @@ libgnome_shell_la_SOURCES = \
shell-wm.c \
shell-wm.h
non_gir_sources = \
non_gir_sources = \
shell-embedded-window-private.h
shell_recorder_sources = \
@ -114,7 +117,7 @@ if BUILD_RECORDER
libgnome_shell_la_SOURCES += $(shell_recorder_sources)
non_gir_sources += $(shell_recorder_non_gir_sources)
noinst_PROGRAMS = test-recorder
noinst_PROGRAMS += test-recorder
test_recorder_CPPFLAGS = $(TEST_SHELL_RECORDER_CFLAGS)
test_recorder_LDADD = $(TEST_SHELL_RECORDER_LIBS)
@ -125,7 +128,7 @@ test_recorder_SOURCES = \
endif BUILD_RECORDER
libgnome_shell_la_gir_sources = \
$(filter-out $(non_gir_sources), $(libgnome_shell_la_SOURCES))
$(filter-out $(non_gir_sources) $(non_gir_toolkit_sources), $(libgnome_shell_la_SOURCES) $(toolkit_sources))
shell-marshal.h: stamp-shell-marshal.h
@true
@ -152,14 +155,16 @@ libgnome_shell_la_LIBADD = \
$(MUTTER_PLUGIN_LIBS) \
$(LIBGNOMEUI_LIBS) \
libbig-1.0.la \
libnbtk-1.0.la \
libgdmuser-1.0.la \
libshell-toolkit.la \
libtray.la
libgnome_shell_la_CPPFLAGS = $(gnome_shell_cflags)
typelibdir = $(pkglibdir)
typelib_DATA = Shell-0.1.typelib Big-1.0.typelib
typelib_DATA = Shell-0.1.typelib Big-1.0.typelib Nbtk-1.0.typelib
Shell-0.1.gir: $(mutter) $(G_IR_SCANNER) Big-1.0.gir libgnome-shell.la Makefile
Shell-0.1.gir: $(mutter) $(G_IR_SCANNER) Big-1.0.gir Nbtk-1.0.gir libgnome-shell.la Makefile
$(AM_V_GEN) $(G_IR_SCANNER) \
--namespace=Shell \
--nsversion=0.1 \
@ -169,6 +174,7 @@ Shell-0.1.gir: $(mutter) $(G_IR_SCANNER) Big-1.0.gir libgnome-shell.la Makefile
--libtool="$(LIBTOOL)" \
--add-include-path=$(builddir) \
--include=Big-1.0 \
--include=Nbtk-1.0 \
--program=mutter \
--program-arg=--mutter-plugins=$$(pwd)/libgnome-shell.la \
$(addprefix $(srcdir)/,$(libgnome_shell_la_gir_sources)) \
@ -179,14 +185,14 @@ CLEANFILES += Shell-0.1.gir
# The dependency on libgnome-shell.la here is because g-ir-compiler opens it
# (not the fake library, since we've already done the rewriting)
Shell-0.1.typelib: libgnome-shell.la Shell-0.1.gir Big-1.0.gir
$(AM_V_GEN) LD_LIBRARY_PATH=.$${LD_LIBRARY_PATH:+:$$LD_LIBRARY_PATH} \
$(AM_V_GEN) \
$(G_IR_COMPILER) \
--includedir=. \
--includedir=$(MUTTER_LIB_DIR)/mutter/ \
Shell-0.1.gir -o $@
CLEANFILES += Shell-0.1.typelib
Big-1.0.gir: $(mutter) $(G_IR_SCANNER) libgnome-shell.la libbig-1.0.la $(srcdir)/big-enum-types.h Makefile
Big-1.0.gir: $(mutter) $(G_IR_SCANNER) libgnome-shell.la libbig-1.0.la Makefile
$(AM_V_GEN) $(G_IR_SCANNER) \
--namespace=Big \
--nsversion=1.0 \
@ -203,6 +209,54 @@ Big-1.0.gir: $(mutter) $(G_IR_SCANNER) libgnome-shell.la libbig-1.0.la $(srcdir)
CLEANFILES += Big-1.0.gir
Big-1.0.typelib: libbig-1.0.la Big-1.0.gir
$(AM_V_GEN) LD_LIBRARY_PATH=.$${LD_LIBRARY_PATH:+:$$LD_LIBRARY_PATH} \
$(G_IR_COMPILER) Big-1.0.gir -o $@
$(AM_V_GEN) $(G_IR_COMPILER) Big-1.0.gir -o $@
CLEANFILES += Big-1.0.typelib
toolkit_gir_sources = \
$(filter-out $(non_gir_toolkit_sources), $(toolkit_sources))
# Since the Shell namepace includes both the code in toolkit/ that our fork of
# NBTK depends upon and the code in this directory that depends on NBTK, We have a
# circular dependency when generating the girs and typelibs. We work around this
# by generating a Toolkit gir, using it to build the Nbtk gir then sed'ing the
# reference out of the generated gir.
Toolkit-0.1.gir: $(mutter) $(G_IR_SCANNER) libgnome-shell.la libshell-toolkit.la Makefile
$(AM_V_GEN) $(G_IR_SCANNER) \
--namespace=Shell \
--nsversion=0.1 \
--include=Clutter-1.0 \
--libtool="$(LIBTOOL)" \
--program=mutter \
--program-arg=--mutter-plugins=$$(pwd)/libgnome-shell.la \
$(addprefix $(srcdir)/,$(toolkit_gir_sources)) \
$(TOOLKIT_CFLAGS) \
-o $@
CLEANFILES += Toolkit-1.0.gir
Nbtk-1.0.gir: $(mutter) $(G_IR_SCANNER) Toolkit-0.1.gir libgnome-shell.la libnbtk-1.0.la Makefile
$(AM_V_GEN) $(G_IR_SCANNER) \
--namespace=Nbtk \
--nsversion=1.0 \
--include=Clutter-1.0 \
--include=Gtk-2.0 \
--add-include-path=$(builddir) \
--include=Toolkit-0.1 \
--libtool="$(LIBTOOL)" \
--program=mutter \
--program-arg=--mutter-plugins=$$(pwd)/libgnome-shell.la \
-DNBTK_COMPILATION \
$(addprefix $(srcdir)/,$(nbtk_source_h)) \
$(addprefix $(srcdir)/,$(nbtk_source_c)) \
$(srcdir)/nbtk-enum-types.h \
$(NBTK_CFLAGS) \
-o $@.tmp && \
sed -e '/"Toolkit"/d' < $@.tmp > $@
CLEANFILES += Nbtk-1.0.gir
Nbtk-1.0.typelib: Nbtk-1.0.gir
$(AM_V_GEN) $(G_IR_COMPILER) \
--includedir=. \
--includedir=$(MUTTER_LIB_DIR)/mutter/ \
$< -o $@
CLEANFILES += Nbtk-1.0.typelib

View File

@ -268,6 +268,52 @@ corner_get(guint radius,
return corner;
}
/* To match the CSS specification, we want the border to look like it was
* drawn over the background. But actually drawing the border over the
* background will produce slightly bad antialiasing at the edges, so
* compute the effective border color instead.
*/
#define NORM(x) (t = (x) + 127, (t + (t >> 8)) >> 8)
#define MULT(c,a) NORM(c*a)
static void
premultiply (ClutterColor *color)
{
guint t;
color->red = MULT (color->red, color->alpha);
color->green = MULT (color->green, color->alpha);
color->blue = MULT (color->blue, color->alpha);
}
static void
unpremultiply (ClutterColor *color)
{
if (color->alpha != 0) {
color->red = (color->red * 255 + 127) / color->alpha;
color->green = (color->green * 255 + 127) / color->alpha;
color->blue = (color->blue * 255 + 127) / color->alpha;
}
}
static void
over (const ClutterColor *source,
const ClutterColor *destination,
ClutterColor *result)
{
guint t;
ClutterColor src = *source;
ClutterColor dst = *destination;
premultiply (&src);
premultiply (&dst);
result->alpha = src.alpha + NORM ((255 - src.alpha) * dst.alpha);
result->red = src.red + NORM ((255 - src.alpha) * dst.red);
result->green = src.green + NORM ((255 - src.alpha) * dst.green);
result->blue = src.blue + NORM ((255 - src.alpha) * dst.blue);
unpremultiply (result);
}
static void
big_rectangle_update_corners(BigRectangle *rectangle)
{
@ -278,6 +324,7 @@ big_rectangle_update_corners(BigRectangle *rectangle)
if (rectangle->radius != 0) {
ClutterColor *color;
ClutterColor *border_color;
ClutterColor effective_border;
guint border_width;
g_object_get(rectangle,
@ -286,10 +333,12 @@ big_rectangle_update_corners(BigRectangle *rectangle)
"color", &color,
NULL);
over (border_color, color, &effective_border);
corner = corner_get(rectangle->radius,
color,
border_width,
border_color);
&effective_border);
clutter_color_free(border_color);
clutter_color_free(color);
@ -329,12 +378,10 @@ big_rectangle_paint(ClutterActor *actor)
rectangle = BIG_RECTANGLE(actor);
if (rectangle->radius == 0) {
/* In that case we are no different than our parent class,
* so don't bother */
CLUTTER_ACTOR_CLASS(big_rectangle_parent_class)->paint(actor);
return;
}
/* We can't chain up, even when we the radius is 0, because of the different
* interpretation of the border/background relationship here than for
* ClutterRectangle.
*/
if (rectangle->corners_dirty)
big_rectangle_update_corners(rectangle);
@ -345,6 +392,9 @@ big_rectangle_paint(ClutterActor *actor)
"color", &color,
NULL);
if (border_color->alpha == 0 && color->alpha == 0)
goto out;
actor_opacity = clutter_actor_get_paint_opacity (actor);
clutter_actor_get_allocation_box(actor, &box);
@ -358,6 +408,11 @@ big_rectangle_paint(ClutterActor *actor)
radius = rectangle->radius;
/* Optimization; if the border is transparent, it just looks like part of
* the background */
if (radius == 0 && border_color->alpha == 0)
border_width = 0;
max = MAX(border_width, radius);
if (radius != 0) {
@ -393,33 +448,54 @@ big_rectangle_paint(ClutterActor *actor)
}
if (border_width != 0) {
ClutterColor effective_border;
over (border_color, color, &effective_border);
if (!rectangle->border_material)
rectangle->border_material = cogl_material_new ();
cogl_color_set_from_4ub(&tmp_color,
border_color->red,
border_color->green,
border_color->blue,
actor_opacity * border_color->alpha / 255);
effective_border.red,
effective_border.green,
effective_border.blue,
actor_opacity * effective_border.alpha / 255);
cogl_color_premultiply (&tmp_color);
cogl_material_set_color(rectangle->border_material, &tmp_color);
cogl_set_source(rectangle->border_material);
/* NORTH */
cogl_rectangle(max, 0,
width - max, border_width);
if (radius > 0) { /* skip corners */
/* NORTH */
cogl_rectangle(max, 0,
width - max, border_width);
/* EAST */
cogl_rectangle(width - border_width, max,
width, height - max);
/* EAST */
cogl_rectangle(width - border_width, max,
width, height - max);
/* SOUTH */
cogl_rectangle(max, height - border_width,
width - max, height);
/* SOUTH */
cogl_rectangle(max, height - border_width,
width - max, height);
/* WEST */
cogl_rectangle(0, max,
border_width, height - max);
/* WEST */
cogl_rectangle(0, max,
border_width, height - max);
} else { /* include corners */
/* NORTH */
cogl_rectangle(0, 0,
width, border_width);
/* EAST */
cogl_rectangle(width - border_width, border_width,
width, height - border_width);
/* SOUTH */
cogl_rectangle(0, height - border_width,
width, height);
/* WEST */
cogl_rectangle(0, border_width,
border_width, height - border_width);
}
}
if (!rectangle->background_material)
@ -455,6 +531,7 @@ big_rectangle_paint(ClutterActor *actor)
cogl_rectangle(border_width, max,
width - border_width, height - max);
out:
clutter_color_free(border_color);
clutter_color_free(color);
}

View File

@ -1,64 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#include <mutter-plugin.h>
ClutterActor *
mutter_plugin_get_overlay_group (MutterPlugin *plugin)
{
return NULL;
}
ClutterActor *
mutter_plugin_get_stage (MutterPlugin *plugin)
{
return NULL;
}
GList *
mutter_plugin_get_windows (MutterPlugin *plugin)
{
return NULL;
}
void
mutter_plugin_query_screen_size (MutterPlugin *plugin,
int *width,
int *height)
{
}
void
mutter_plugin_set_stage_input_area (MutterPlugin *plugin,
gint x, gint y, gint width, gint height)
{
}
MetaScreen *
mutter_plugin_get_screen (MutterPlugin *plugin)
{
return NULL;
}
ClutterActor *
mutter_plugin_get_window_group (MutterPlugin *plugin)
{
return NULL;
}
Display *
meta_display_get_xdisplay (MetaDisplay *display)
{
return NULL;
}
MetaDisplay *
meta_screen_get_display (MetaScreen *display)
{
return NULL;
}
Window
meta_screen_get_xroot (MetaScreen *display)
{
return None;
}

768
src/nbtk/nbtk-adjustment.c Normal file
View File

@ -0,0 +1,768 @@
/*
* nbtk-adjustment.c: Adjustment object
*
* Copyright (C) 2008 OpenedHand
* Copyright (c) 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* Written by: Chris Lord <chris@openedhand.com>, inspired by GtkAdjustment
* Port to Nbtk by: Robert Staudinger <robsta@openedhand.com>
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <glib-object.h>
#include <clutter/clutter.h>
#include "nbtk-adjustment.h"
#include "nbtk-marshal.h"
#include "nbtk-private.h"
G_DEFINE_TYPE (NbtkAdjustment, nbtk_adjustment, G_TYPE_OBJECT)
#define ADJUSTMENT_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NBTK_TYPE_ADJUSTMENT, NbtkAdjustmentPrivate))
struct _NbtkAdjustmentPrivate
{
/* Do not sanity-check values while constructing,
* not all properties may be set yet. */
gboolean is_constructing : 1;
gdouble lower;
gdouble upper;
gdouble value;
gdouble step_increment;
gdouble page_increment;
gdouble page_size;
/* For interpolation */
ClutterTimeline *interpolation;
gdouble old_position;
gdouble new_position;
/* For elasticity */
gboolean elastic;
guint bounce_source;
ClutterAlpha *bounce_alpha;
};
enum
{
PROP_0,
PROP_LOWER,
PROP_UPPER,
PROP_VALUE,
PROP_STEP_INC,
PROP_PAGE_INC,
PROP_PAGE_SIZE,
PROP_ELASTIC,
};
enum
{
CHANGED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0, };
static gboolean nbtk_adjustment_set_lower (NbtkAdjustment *adjustment,
gdouble lower);
static gboolean nbtk_adjustment_set_upper (NbtkAdjustment *adjustment,
gdouble upper);
static gboolean nbtk_adjustment_set_step_increment (NbtkAdjustment *adjustment,
gdouble step);
static gboolean nbtk_adjustment_set_page_increment (NbtkAdjustment *adjustment,
gdouble page);
static gboolean nbtk_adjustment_set_page_size (NbtkAdjustment *adjustment,
gdouble size);
static void
nbtk_adjustment_constructed (GObject *object)
{
GObjectClass *g_class;
NbtkAdjustment *self = NBTK_ADJUSTMENT (object);
g_class = G_OBJECT_CLASS (nbtk_adjustment_parent_class);
/* The docs say we're suppose to chain up, but would crash without
* some extra care. */
if (g_class && g_class->constructed &&
g_class->constructed != nbtk_adjustment_constructed)
{
g_class->constructed (object);
}
NBTK_ADJUSTMENT (self)->priv->is_constructing = FALSE;
nbtk_adjustment_clamp_page (self, self->priv->lower, self->priv->upper);
}
static void
nbtk_adjustment_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
NbtkAdjustmentPrivate *priv = NBTK_ADJUSTMENT (gobject)->priv;
switch (prop_id)
{
case PROP_LOWER:
g_value_set_double (value, priv->lower);
break;
case PROP_UPPER:
g_value_set_double (value, priv->upper);
break;
case PROP_VALUE:
g_value_set_double (value, priv->value);
break;
case PROP_STEP_INC:
g_value_set_double (value, priv->step_increment);
break;
case PROP_PAGE_INC:
g_value_set_double (value, priv->page_increment);
break;
case PROP_PAGE_SIZE:
g_value_set_double (value, priv->page_size);
break;
case PROP_ELASTIC:
g_value_set_boolean (value, priv->elastic);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
nbtk_adjustment_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
NbtkAdjustment *adj = NBTK_ADJUSTMENT (gobject);
switch (prop_id)
{
case PROP_LOWER:
nbtk_adjustment_set_lower (adj, g_value_get_double (value));
break;
case PROP_UPPER:
nbtk_adjustment_set_upper (adj, g_value_get_double (value));
break;
case PROP_VALUE:
nbtk_adjustment_set_value (adj, g_value_get_double (value));
break;
case PROP_STEP_INC:
nbtk_adjustment_set_step_increment (adj, g_value_get_double (value));
break;
case PROP_PAGE_INC:
nbtk_adjustment_set_page_increment (adj, g_value_get_double (value));
break;
case PROP_PAGE_SIZE:
nbtk_adjustment_set_page_size (adj, g_value_get_double (value));
break;
case PROP_ELASTIC:
nbtk_adjustment_set_elastic (adj, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
stop_interpolation (NbtkAdjustment *adjustment)
{
NbtkAdjustmentPrivate *priv = adjustment->priv;
if (priv->interpolation)
{
clutter_timeline_stop (priv->interpolation);
g_object_unref (priv->interpolation);
priv->interpolation = NULL;
if (priv->bounce_alpha)
{
g_object_unref (priv->bounce_alpha);
priv->bounce_alpha = NULL;
}
}
if (priv->bounce_source)
{
g_source_remove (priv->bounce_source);
priv->bounce_source = 0;
}
}
static void
nbtk_adjustment_dispose (GObject *object)
{
stop_interpolation (NBTK_ADJUSTMENT (object));
G_OBJECT_CLASS (nbtk_adjustment_parent_class)->dispose (object);
}
static void
nbtk_adjustment_class_init (NbtkAdjustmentClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (NbtkAdjustmentPrivate));
object_class->constructed = nbtk_adjustment_constructed;
object_class->get_property = nbtk_adjustment_get_property;
object_class->set_property = nbtk_adjustment_set_property;
object_class->dispose = nbtk_adjustment_dispose;
g_object_class_install_property (object_class,
PROP_LOWER,
g_param_spec_double ("lower",
"Lower",
"Lower bound",
-G_MAXDOUBLE,
G_MAXDOUBLE,
0.0,
NBTK_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class,
PROP_UPPER,
g_param_spec_double ("upper",
"Upper",
"Upper bound",
-G_MAXDOUBLE,
G_MAXDOUBLE,
0.0,
NBTK_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class,
PROP_VALUE,
g_param_spec_double ("value",
"Value",
"Current value",
-G_MAXDOUBLE,
G_MAXDOUBLE,
0.0,
NBTK_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class,
PROP_STEP_INC,
g_param_spec_double ("step-increment",
"Step Increment",
"Step increment",
0.0,
G_MAXDOUBLE,
0.0,
NBTK_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class,
PROP_PAGE_INC,
g_param_spec_double ("page-increment",
"Page Increment",
"Page increment",
0.0,
G_MAXDOUBLE,
0.0,
NBTK_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class,
PROP_PAGE_SIZE,
g_param_spec_double ("page-size",
"Page Size",
"Page size",
0.0,
G_MAXDOUBLE,
0.0,
NBTK_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class,
PROP_ELASTIC,
g_param_spec_boolean ("elastic",
"Elastic",
"Make interpolation "
"behave in an "
"'elastic' way and "
"stop clamping value.",
FALSE,
NBTK_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
/**
* NbtkAdjustment::changed:
*
* Emitted when any of the adjustment values have changed
*/
signals[CHANGED] =
g_signal_new ("changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NbtkAdjustmentClass, changed),
NULL, NULL,
_nbtk_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static void
nbtk_adjustment_init (NbtkAdjustment *self)
{
self->priv = ADJUSTMENT_PRIVATE (self);
self->priv->is_constructing = TRUE;
}
NbtkAdjustment *
nbtk_adjustment_new (gdouble value,
gdouble lower,
gdouble upper,
gdouble step_increment,
gdouble page_increment,
gdouble page_size)
{
return g_object_new (NBTK_TYPE_ADJUSTMENT,
"value", value,
"lower", lower,
"upper", upper,
"step-increment", step_increment,
"page-increment", page_increment,
"page-size", page_size,
NULL);
}
gdouble
nbtk_adjustment_get_value (NbtkAdjustment *adjustment)
{
NbtkAdjustmentPrivate *priv;
g_return_val_if_fail (NBTK_IS_ADJUSTMENT (adjustment), 0);
priv = adjustment->priv;
if (priv->interpolation)
{
return MAX (priv->lower,
MIN (priv->upper - priv->page_size,
priv->new_position));
}
else
return priv->value;
}
void
nbtk_adjustment_set_value (NbtkAdjustment *adjustment,
gdouble value)
{
NbtkAdjustmentPrivate *priv;
g_return_if_fail (NBTK_IS_ADJUSTMENT (adjustment));
priv = adjustment->priv;
stop_interpolation (adjustment);
/* Defer clamp until after construction. */
if (!priv->is_constructing)
{
if (!priv->elastic)
value = CLAMP (value,
priv->lower,
MAX (priv->lower, priv->upper - priv->page_size));
}
if (priv->value != value)
{
priv->value = value;
g_object_notify (G_OBJECT (adjustment), "value");
}
}
void
nbtk_adjustment_clamp_page (NbtkAdjustment *adjustment,
gdouble lower,
gdouble upper)
{
NbtkAdjustmentPrivate *priv;
gboolean changed;
g_return_if_fail (NBTK_IS_ADJUSTMENT (adjustment));
priv = adjustment->priv;
stop_interpolation (adjustment);
lower = CLAMP (lower, priv->lower, priv->upper - priv->page_size);
upper = CLAMP (upper, priv->lower + priv->page_size, priv->upper);
changed = FALSE;
if (priv->value + priv->page_size > upper)
{
priv->value = upper - priv->page_size;
changed = TRUE;
}
if (priv->value < lower)
{
priv->value = lower;
changed = TRUE;
}
if (changed)
g_object_notify (G_OBJECT (adjustment), "value");
}
static gboolean
nbtk_adjustment_set_lower (NbtkAdjustment *adjustment,
gdouble lower)
{
NbtkAdjustmentPrivate *priv = adjustment->priv;
if (priv->lower != lower)
{
priv->lower = lower;
g_signal_emit (adjustment, signals[CHANGED], 0);
g_object_notify (G_OBJECT (adjustment), "lower");
/* Defer clamp until after construction. */
if (!priv->is_constructing)
nbtk_adjustment_clamp_page (adjustment, priv->lower, priv->upper);
return TRUE;
}
return FALSE;
}
static gboolean
nbtk_adjustment_set_upper (NbtkAdjustment *adjustment,
gdouble upper)
{
NbtkAdjustmentPrivate *priv = adjustment->priv;
if (priv->upper != upper)
{
priv->upper = upper;
g_signal_emit (adjustment, signals[CHANGED], 0);
g_object_notify (G_OBJECT (adjustment), "upper");
/* Defer clamp until after construction. */
if (!priv->is_constructing)
nbtk_adjustment_clamp_page (adjustment, priv->lower, priv->upper);
return TRUE;
}
return FALSE;
}
static gboolean
nbtk_adjustment_set_step_increment (NbtkAdjustment *adjustment,
gdouble step)
{
NbtkAdjustmentPrivate *priv = adjustment->priv;
if (priv->step_increment != step)
{
priv->step_increment = step;
g_signal_emit (adjustment, signals[CHANGED], 0);
g_object_notify (G_OBJECT (adjustment), "step-increment");
return TRUE;
}
return FALSE;
}
static gboolean
nbtk_adjustment_set_page_increment (NbtkAdjustment *adjustment,
gdouble page)
{
NbtkAdjustmentPrivate *priv = adjustment->priv;
if (priv->page_increment != page)
{
priv->page_increment = page;
g_signal_emit (adjustment, signals[CHANGED], 0);
g_object_notify (G_OBJECT (adjustment), "page-increment");
return TRUE;
}
return FALSE;
}
static gboolean
nbtk_adjustment_set_page_size (NbtkAdjustment *adjustment,
gdouble size)
{
NbtkAdjustmentPrivate *priv = adjustment->priv;
if (priv->page_size != size)
{
priv->page_size = size;
g_signal_emit (adjustment, signals[CHANGED], 0);
g_object_notify (G_OBJECT (adjustment), "page_size");
/* Well explicitely clamp after construction. */
if (!priv->is_constructing)
nbtk_adjustment_clamp_page (adjustment, priv->lower, priv->upper);
return TRUE;
}
return FALSE;
}
void
nbtk_adjustment_set_values (NbtkAdjustment *adjustment,
gdouble value,
gdouble lower,
gdouble upper,
gdouble step_increment,
gdouble page_increment,
gdouble page_size)
{
NbtkAdjustmentPrivate *priv;
gboolean emit_changed = FALSE;
g_return_if_fail (NBTK_IS_ADJUSTMENT (adjustment));
g_return_if_fail (page_size >= 0 && page_size <= G_MAXDOUBLE);
g_return_if_fail (step_increment >= 0 && step_increment <= G_MAXDOUBLE);
g_return_if_fail (page_increment >= 0 && page_increment <= G_MAXDOUBLE);
priv = adjustment->priv;
stop_interpolation (adjustment);
emit_changed = FALSE;
g_object_freeze_notify (G_OBJECT (adjustment));
emit_changed |= nbtk_adjustment_set_lower (adjustment, lower);
emit_changed |= nbtk_adjustment_set_upper (adjustment, upper);
emit_changed |= nbtk_adjustment_set_step_increment (adjustment, step_increment);
emit_changed |= nbtk_adjustment_set_page_increment (adjustment, page_increment);
emit_changed |= nbtk_adjustment_set_page_size (adjustment, page_size);
if (value != priv->value)
{
nbtk_adjustment_set_value (adjustment, value);
emit_changed = TRUE;
}
if (emit_changed)
g_signal_emit (G_OBJECT (adjustment), signals[CHANGED], 0);
g_object_thaw_notify (G_OBJECT (adjustment));
}
void
nbtk_adjustment_get_values (NbtkAdjustment *adjustment,
gdouble *value,
gdouble *lower,
gdouble *upper,
gdouble *step_increment,
gdouble *page_increment,
gdouble *page_size)
{
NbtkAdjustmentPrivate *priv;
g_return_if_fail (NBTK_IS_ADJUSTMENT (adjustment));
priv = adjustment->priv;
if (lower)
*lower = priv->lower;
if (upper)
*upper = priv->upper;
if (value)
*value = nbtk_adjustment_get_value (adjustment);
if (step_increment)
*step_increment = priv->step_increment;
if (page_increment)
*page_increment = priv->page_increment;
if (page_size)
*page_size = priv->page_size;
}
static void
interpolation_new_frame_cb (ClutterTimeline *timeline,
guint msecs,
NbtkAdjustment *adjustment)
{
NbtkAdjustmentPrivate *priv = adjustment->priv;
priv->interpolation = NULL;
if (priv->elastic)
{
gdouble progress = clutter_alpha_get_alpha (priv->bounce_alpha) / 1.0;
gdouble dx = priv->old_position
+ (priv->new_position - priv->old_position)
* progress;
nbtk_adjustment_set_value (adjustment, dx);
}
else
nbtk_adjustment_set_value (adjustment,
priv->old_position +
(priv->new_position - priv->old_position) *
clutter_timeline_get_progress (timeline));
priv->interpolation = timeline;
}
static void
interpolation_completed_cb (ClutterTimeline *timeline,
NbtkAdjustment *adjustment)
{
NbtkAdjustmentPrivate *priv = adjustment->priv;
stop_interpolation (adjustment);
nbtk_adjustment_set_value (adjustment, priv->new_position);
}
/* Note, there's super-optimal code that does a similar thing in
* clutter-alpha.c
*
* Tried this instead of CLUTTER_ALPHA_SINE_INC, but I think SINE_INC looks
* better. Leaving code here in case this is revisited.
*/
/*
static guint32
bounce_alpha_func (ClutterAlpha *alpha,
gpointer user_data)
{
ClutterFixed progress, angle;
ClutterTimeline *timeline = clutter_alpha_get_timeline (alpha);
progress = clutter_timeline_get_progressx (timeline);
angle = clutter_qmulx (CFX_PI_2 + CFX_PI_4/2, progress);
return clutter_sinx (angle) +
(CFX_ONE - clutter_sinx (CFX_PI_2 + CFX_PI_4/2));
}
*/
void
nbtk_adjustment_interpolate (NbtkAdjustment *adjustment,
gdouble value,
guint duration)
{
NbtkAdjustmentPrivate *priv = adjustment->priv;
stop_interpolation (adjustment);
if (duration <= 1)
{
nbtk_adjustment_set_value (adjustment, value);
return;
}
priv->old_position = priv->value;
priv->new_position = value;
priv->interpolation = clutter_timeline_new (duration);
if (priv->elastic)
priv->bounce_alpha = clutter_alpha_new_full (priv->interpolation,
CLUTTER_LINEAR);
g_signal_connect (priv->interpolation,
"new-frame",
G_CALLBACK (interpolation_new_frame_cb),
adjustment);
g_signal_connect (priv->interpolation,
"completed",
G_CALLBACK (interpolation_completed_cb),
adjustment);
clutter_timeline_start (priv->interpolation);
}
gboolean
nbtk_adjustment_get_elastic (NbtkAdjustment *adjustment)
{
return adjustment->priv->elastic;
}
void
nbtk_adjustment_set_elastic (NbtkAdjustment *adjustment,
gboolean elastic)
{
adjustment->priv->elastic = elastic;
}
gboolean
nbtk_adjustment_clamp (NbtkAdjustment *adjustment,
gboolean interpolate,
guint duration)
{
NbtkAdjustmentPrivate *priv = adjustment->priv;
gdouble dest = priv->value;
if (priv->value < priv->lower)
dest = priv->lower;
if (priv->value > priv->upper - priv->page_size)
dest = priv->upper - priv->page_size;
if (dest != priv->value)
{
if (interpolate)
nbtk_adjustment_interpolate (adjustment, dest, duration);
else
nbtk_adjustment_set_value (adjustment, dest);
return TRUE;
}
return FALSE;
}

121
src/nbtk/nbtk-adjustment.h Normal file
View File

@ -0,0 +1,121 @@
/*
* nbtk-adjustment.h: Adjustment object
*
* Copyright 2008 OpenedHand
* Copyright 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* Written by: Chris Lord <chris@openedhand.com>, inspired by GtkAdjustment
* Port to Nbtk by: Robert Staudinger <robsta@openedhand.com>
*
*/
#if !defined(NBTK_H_INSIDE) && !defined(NBTK_COMPILATION)
#error "Only <nbtk/nbtk.h> can be included directly.h"
#endif
#ifndef __NBTK_ADJUSTMENT_H__
#define __NBTK_ADJUSTMENT_H__
#include <glib-object.h>
#include <clutter/clutter.h>
G_BEGIN_DECLS
#define NBTK_TYPE_ADJUSTMENT (nbtk_adjustment_get_type())
#define NBTK_ADJUSTMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NBTK_TYPE_ADJUSTMENT, NbtkAdjustment))
#define NBTK_IS_ADJUSTMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NBTK_TYPE_ADJUSTMENT))
#define NBTK_ADJUSTMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NBTK_TYPE_ADJUSTMENT, NbtkAdjustmentClass))
#define NBTK_IS_ADJUSTMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NBTK_TYPE_ADJUSTMENT))
#define NBTK_ADJUSTMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NBTK_TYPE_ADJUSTMENT, NbtkAdjustmentClass))
typedef struct _NbtkAdjustment NbtkAdjustment;
typedef struct _NbtkAdjustmentPrivate NbtkAdjustmentPrivate;
typedef struct _NbtkAdjustmentClass NbtkAdjustmentClass;
/**
* NbtkAdjustment:
*
* Class for handling an interval between to values. The contents of
* the #NbtkAdjustment are private and should be accessed using the
* public API.
*/
struct _NbtkAdjustment
{
/*< private >*/
GObject parent_instance;
NbtkAdjustmentPrivate *priv;
};
/**
* NbtkAdjustmentClass
* @changed: Class handler for the ::changed signal.
*
* Base class for #NbtkAdjustment.
*/
struct _NbtkAdjustmentClass
{
/*< private >*/
GObjectClass parent_class;
/*< public >*/
void (* changed) (NbtkAdjustment *adjustment);
};
GType nbtk_adjustment_get_type (void) G_GNUC_CONST;
NbtkAdjustment *nbtk_adjustment_new (gdouble value,
gdouble lower,
gdouble upper,
gdouble step_increment,
gdouble page_increment,
gdouble page_size);
gdouble nbtk_adjustment_get_value (NbtkAdjustment *adjustment);
void nbtk_adjustment_set_value (NbtkAdjustment *adjustment,
gdouble value);
void nbtk_adjustment_clamp_page (NbtkAdjustment *adjustment,
gdouble lower,
gdouble upper);
void nbtk_adjustment_set_values (NbtkAdjustment *adjustment,
gdouble value,
gdouble lower,
gdouble upper,
gdouble step_increment,
gdouble page_increment,
gdouble page_size);
void nbtk_adjustment_get_values (NbtkAdjustment *adjustment,
gdouble *value,
gdouble *lower,
gdouble *upper,
gdouble *step_increment,
gdouble *page_increment,
gdouble *page_size);
void nbtk_adjustment_interpolate (NbtkAdjustment *adjustment,
gdouble value,
guint duration);
gboolean nbtk_adjustment_get_elastic (NbtkAdjustment *adjustment);
void nbtk_adjustment_set_elastic (NbtkAdjustment *adjustment,
gboolean elastic);
gboolean nbtk_adjustment_clamp (NbtkAdjustment *adjustment,
gboolean interpolate,
guint duration);
G_END_DECLS
#endif /* __NBTK_ADJUSTMENT_H__ */

739
src/nbtk/nbtk-bin.c Normal file
View File

@ -0,0 +1,739 @@
/*
* nbtk-bin.c: Basic container actor
*
* Copyright (c) 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* Written by: Emmanuele Bassi <ebassi@linux.intel.com>
*
*/
/**
* SECTION:nbtk-bin
* @short_description: a simple container with one actor
*
* #NbtkBin is a simple container capable of having only one
* #ClutterActor as a child.
*
* #NbtkBin inherits from #NbtkWidget, so it is fully themable.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <clutter/clutter.h>
#include "nbtk-bin.h"
#include "nbtk-enum-types.h"
#include "nbtk-private.h"
#define NBTK_BIN_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NBTK_TYPE_BIN, NbtkBinPrivate))
struct _NbtkBinPrivate
{
ClutterActor *child;
NbtkAlignment x_align;
NbtkAlignment y_align;
guint x_fill : 1;
guint y_fill : 1;
};
enum
{
PROP_0,
PROP_CHILD,
PROP_X_ALIGN,
PROP_Y_ALIGN,
PROP_X_FILL,
PROP_Y_FILL
};
static void clutter_container_iface_init (ClutterContainerIface *iface);
G_DEFINE_TYPE_WITH_CODE (NbtkBin, nbtk_bin, NBTK_TYPE_WIDGET,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
clutter_container_iface_init));
void
_nbtk_bin_get_align_factors (NbtkBin *bin,
gdouble *x_align,
gdouble *y_align)
{
NbtkBinPrivate *priv = bin->priv;
gdouble factor;
switch (priv->x_align)
{
case NBTK_ALIGN_LEFT:
factor = 0.0;
break;
case NBTK_ALIGN_CENTER:
factor = 0.5;
break;
case NBTK_ALIGN_RIGHT:
factor = 1.0;
break;
default:
factor = 0.0;
break;
}
if (x_align)
*x_align = factor;
switch (priv->y_align)
{
case NBTK_ALIGN_TOP:
factor = 0.0;
break;
case NBTK_ALIGN_CENTER:
factor = 0.5;
break;
case NBTK_ALIGN_BOTTOM:
factor = 1.0;
break;
default:
factor = 0.0;
break;
}
if (y_align)
*y_align = factor;
}
static void
nbtk_bin_add (ClutterContainer *container,
ClutterActor *actor)
{
nbtk_bin_set_child (NBTK_BIN (container), actor);
}
static void
nbtk_bin_remove (ClutterContainer *container,
ClutterActor *actor)
{
NbtkBinPrivate *priv = NBTK_BIN (container)->priv;
if (priv->child == actor)
nbtk_bin_set_child (NBTK_BIN (container), NULL);
}
static void
nbtk_bin_foreach (ClutterContainer *container,
ClutterCallback callback,
gpointer user_data)
{
NbtkBinPrivate *priv = NBTK_BIN (container)->priv;
if (priv->child)
callback (priv->child, user_data);
}
static void
clutter_container_iface_init (ClutterContainerIface *iface)
{
iface->add = nbtk_bin_add;
iface->remove = nbtk_bin_remove;
iface->foreach = nbtk_bin_foreach;
}
static void
nbtk_bin_paint (ClutterActor *self)
{
NbtkBinPrivate *priv = NBTK_BIN (self)->priv;
/* allow NbtkWidget to paint the background */
CLUTTER_ACTOR_CLASS (nbtk_bin_parent_class)->paint (self);
/* the pain our child */
if (priv->child)
clutter_actor_paint (priv->child);
}
static void
nbtk_bin_pick (ClutterActor *self,
const ClutterColor *pick_color)
{
NbtkBinPrivate *priv = NBTK_BIN (self)->priv;
/* get the default pick implementation */
CLUTTER_ACTOR_CLASS (nbtk_bin_parent_class)->pick (self, pick_color);
if (priv->child)
clutter_actor_paint (priv->child);
}
static void
nbtk_bin_allocate (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
NbtkBinPrivate *priv = NBTK_BIN (self)->priv;
CLUTTER_ACTOR_CLASS (nbtk_bin_parent_class)->allocate (self, box,
flags);
if (priv->child)
{
ShellThemeNode *theme_node = nbtk_widget_get_theme_node (NBTK_WIDGET (self));
gfloat natural_width, natural_height;
gfloat min_width, min_height;
gfloat child_width, child_height;
gfloat available_width, available_height;
ClutterRequestMode request;
ClutterActorBox content_box;
ClutterActorBox allocation = { 0, };
gdouble x_align, y_align;
shell_theme_node_get_content_box (theme_node, box, &content_box);
_nbtk_bin_get_align_factors (NBTK_BIN (self), &x_align, &y_align);
available_width = content_box.x2 - content_box.x1;
available_height = content_box.y2 - content_box.y1;
if (available_width < 0)
available_width = 0;
if (available_height < 0)
available_height = 0;
if (priv->x_fill)
{
allocation.x1 = (int) content_box.x1;
allocation.x2 = (int) content_box.x2;
}
if (priv->y_fill)
{
allocation.y1 = (int) content_box.y1;
allocation.y2 = (int) content_box.y2;
}
/* if we are filling horizontally and vertically then we're done */
if (priv->x_fill && priv->y_fill)
{
clutter_actor_allocate (priv->child, &allocation, flags);
return;
}
request = CLUTTER_REQUEST_HEIGHT_FOR_WIDTH;
g_object_get (G_OBJECT (priv->child), "request-mode", &request, NULL);
if (request == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
{
clutter_actor_get_preferred_width (priv->child, available_height,
&min_width,
&natural_width);
child_width = CLAMP (natural_width, min_width, available_width);
clutter_actor_get_preferred_height (priv->child, child_width,
&min_height,
&natural_height);
child_height = CLAMP (natural_height, min_height, available_height);
}
else
{
clutter_actor_get_preferred_height (priv->child, available_width,
&min_height,
&natural_height);
child_height = CLAMP (natural_height, min_height, available_height);
clutter_actor_get_preferred_width (priv->child, child_height,
&min_width,
&natural_width);
child_width = CLAMP (natural_width, min_width, available_width);
}
if (!priv->x_fill)
{
allocation.x1 = content_box.x1 + (int) ((available_width - child_width) * x_align);
allocation.x2 = allocation.x1 + child_width;
}
if (!priv->y_fill)
{
allocation.y1 = content_box.y1 + (int) ((available_height - child_height) * y_align);
allocation.y2 = allocation.y1 + child_height;
}
clutter_actor_allocate (priv->child, &allocation, flags);
}
}
static void
nbtk_bin_get_preferred_width (ClutterActor *self,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
NbtkBinPrivate *priv = NBTK_BIN (self)->priv;
ShellThemeNode *theme_node = nbtk_widget_get_theme_node (NBTK_WIDGET (self));
shell_theme_node_adjust_for_height (theme_node, &for_height);
if (priv->child == NULL)
{
if (min_width_p)
*min_width_p = 0;
if (natural_width_p)
*natural_width_p = 0;
}
else
{
clutter_actor_get_preferred_width (priv->child, for_height,
min_width_p,
natural_width_p);
}
shell_theme_node_adjust_preferred_width (theme_node, min_width_p, natural_width_p);
}
static void
nbtk_bin_get_preferred_height (ClutterActor *self,
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
NbtkBinPrivate *priv = NBTK_BIN (self)->priv;
ShellThemeNode *theme_node = nbtk_widget_get_theme_node (NBTK_WIDGET (self));
shell_theme_node_adjust_for_width (theme_node, &for_width);
if (priv->child == NULL)
{
if (min_height_p)
*min_height_p = 0;
if (natural_height_p)
*natural_height_p = 0;
}
else
{
clutter_actor_get_preferred_height (priv->child, for_width,
min_height_p,
natural_height_p);
}
shell_theme_node_adjust_preferred_height (theme_node, min_height_p, natural_height_p);
}
static void
nbtk_bin_dispose (GObject *gobject)
{
NbtkBinPrivate *priv = NBTK_BIN (gobject)->priv;
if (priv->child)
{
clutter_actor_unparent (priv->child);
priv->child = NULL;
}
G_OBJECT_CLASS (nbtk_bin_parent_class)->dispose (gobject);
}
static void
nbtk_bin_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
NbtkBin *bin = NBTK_BIN (gobject);
switch (prop_id)
{
case PROP_CHILD:
nbtk_bin_set_child (bin, g_value_get_object (value));
break;
case PROP_X_ALIGN:
nbtk_bin_set_alignment (bin,
g_value_get_enum (value),
bin->priv->y_align);
break;
case PROP_Y_ALIGN:
nbtk_bin_set_alignment (bin,
bin->priv->x_align,
g_value_get_enum (value));
break;
case PROP_X_FILL:
nbtk_bin_set_fill (bin,
g_value_get_boolean (value),
bin->priv->y_fill);
break;
case PROP_Y_FILL:
nbtk_bin_set_fill (bin,
bin->priv->y_fill,
g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
}
}
static void
nbtk_bin_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
NbtkBinPrivate *priv = NBTK_BIN (gobject)->priv;
switch (prop_id)
{
case PROP_CHILD:
g_value_set_object (value, priv->child);
break;
case PROP_X_FILL:
g_value_set_boolean (value, priv->x_fill);
break;
case PROP_Y_FILL:
g_value_set_boolean (value, priv->y_fill);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
}
}
static void
nbtk_bin_class_init (NbtkBinClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
GParamSpec *pspec;
g_type_class_add_private (klass, sizeof (NbtkBinPrivate));
gobject_class->set_property = nbtk_bin_set_property;
gobject_class->get_property = nbtk_bin_get_property;
gobject_class->dispose = nbtk_bin_dispose;
actor_class->get_preferred_width = nbtk_bin_get_preferred_width;
actor_class->get_preferred_height = nbtk_bin_get_preferred_height;
actor_class->allocate = nbtk_bin_allocate;
actor_class->paint = nbtk_bin_paint;
actor_class->pick = nbtk_bin_pick;
/**
* NbtkBin:child:
*
* The child #ClutterActor of the #NbtkBin container.
*/
pspec = g_param_spec_object ("child",
"Child",
"The child of the Bin",
CLUTTER_TYPE_ACTOR,
NBTK_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_CHILD, pspec);
/**
* NbtkBin:x-align:
*
* The horizontal alignment of the #NbtkBin child.
*/
pspec = g_param_spec_enum ("x-align",
"X Align",
"The horizontal alignment",
NBTK_TYPE_ALIGNMENT,
NBTK_ALIGN_CENTER,
NBTK_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_X_ALIGN, pspec);
/**
* NbtkBin:y-align:
*
* The vertical alignment of the #NbtkBin child.
*/
pspec = g_param_spec_enum ("y-align",
"Y Align",
"The vertical alignment",
NBTK_TYPE_ALIGNMENT,
NBTK_ALIGN_CENTER,
NBTK_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_Y_ALIGN, pspec);
/**
* NbtkBin:x-fill:
*
* Whether the child should fill the horizontal allocation
*/
pspec = g_param_spec_boolean ("x-fill",
"X Fill",
"Whether the child should fill the "
"horizontal allocation",
FALSE,
NBTK_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_X_FILL, pspec);
/**
* NbtkBin:y-fill:
*
* Whether the child should fill the vertical allocation
*/
pspec = g_param_spec_boolean ("y-fill",
"Y Fill",
"Whether the child should fill the "
"vertical allocation",
FALSE,
NBTK_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_Y_FILL, pspec);
}
static void
nbtk_bin_init (NbtkBin *bin)
{
bin->priv = NBTK_BIN_GET_PRIVATE (bin);
bin->priv->x_align = NBTK_ALIGN_CENTER;
bin->priv->y_align = NBTK_ALIGN_CENTER;
}
/**
* nbtk_bin_new:
*
* Creates a new #NbtkBin, a simple container for one child.
*
* Return value: the newly created #NbtkBin actor
*/
NbtkWidget *
nbtk_bin_new (void)
{
return g_object_new (NBTK_TYPE_BIN, NULL);
}
/**
* nbtk_bin_set_child:
* @bin: a #NbtkBin
* @child: a #ClutterActor, or %NULL
*
* Sets @child as the child of @bin.
*
* If @bin already has a child, the previous child is removed.
*/
void
nbtk_bin_set_child (NbtkBin *bin,
ClutterActor *child)
{
NbtkBinPrivate *priv;
g_return_if_fail (NBTK_IS_BIN (bin));
g_return_if_fail (child == NULL || CLUTTER_IS_ACTOR (child));
priv = bin->priv;
if (priv->child == child)
return;
if (priv->child)
{
ClutterActor *old_child = priv->child;
g_object_ref (old_child);
priv->child = NULL;
clutter_actor_unparent (old_child);
g_signal_emit_by_name (bin, "actor-removed", old_child);
g_object_unref (old_child);
}
if (child)
{
priv->child = child;
clutter_actor_set_parent (child, CLUTTER_ACTOR (bin));
g_signal_emit_by_name (bin, "actor-added", priv->child);
}
clutter_actor_queue_relayout (CLUTTER_ACTOR (bin));
g_object_notify (G_OBJECT (bin), "child");
}
/**
* nbtk_bin_get_child:
* @bin: a #NbtkBin
*
* Retrieves a pointer to the child of @bin.
*
* Return value: (transfer none): a #ClutterActor, or %NULL
*/
ClutterActor *
nbtk_bin_get_child (NbtkBin *bin)
{
g_return_val_if_fail (NBTK_IS_BIN (bin), NULL);
return bin->priv->child;
}
/**
* nbtk_bin_set_alignment:
* @bin: a #NbtkBin
* @x_align: horizontal alignment
* @y_align: vertical alignment
*
* Sets the horizontal and vertical alignment of the child
* inside a #NbtkBin.
*/
void
nbtk_bin_set_alignment (NbtkBin *bin,
NbtkAlignment x_align,
NbtkAlignment y_align)
{
NbtkBinPrivate *priv;
gboolean changed = FALSE;
g_return_if_fail (NBTK_IS_BIN (bin));
priv = bin->priv;
g_object_freeze_notify (G_OBJECT (bin));
if (priv->x_align != x_align)
{
priv->x_align = x_align;
g_object_notify (G_OBJECT (bin), "x-align");
changed = TRUE;
}
if (priv->y_align != y_align)
{
priv->y_align = y_align;
g_object_notify (G_OBJECT (bin), "y-align");
changed = TRUE;
}
if (changed)
clutter_actor_queue_relayout (CLUTTER_ACTOR (bin));
g_object_thaw_notify (G_OBJECT (bin));
}
/**
* nbtk_bin_get_alignment:
* @bin: a #NbtkBin
* @x_align: return location for the horizontal alignment, or %NULL
* @y_align: return location for the vertical alignment, or %NULL
*
* Retrieves the horizontal and vertical alignment of the child
* inside a #NbtkBin, as set by nbtk_bin_set_alignment().
*/
void
nbtk_bin_get_alignment (NbtkBin *bin,
NbtkAlignment *x_align,
NbtkAlignment *y_align)
{
NbtkBinPrivate *priv;
g_return_if_fail (NBTK_IS_BIN (bin));
priv = bin->priv;
if (x_align)
*x_align = priv->x_align;
if (y_align)
*y_align = priv->y_align;
}
/**
* nbtk_bin_set_fill:
* @bin: a #NbtkBin
* @x_fill: %TRUE if the child should fill horizontally the @bin
* @y_fill: %TRUE if the child should fill vertically the @bin
*
* Sets whether the child of @bin should fill out the horizontal
* and/or vertical allocation of the parent
*/
void
nbtk_bin_set_fill (NbtkBin *bin,
gboolean x_fill,
gboolean y_fill)
{
NbtkBinPrivate *priv;
gboolean changed = FALSE;
g_return_if_fail (NBTK_IS_BIN (bin));
priv = bin->priv;
g_object_freeze_notify (G_OBJECT (bin));
if (priv->x_fill != x_fill)
{
priv->x_fill = x_fill;
changed = TRUE;
g_object_notify (G_OBJECT (bin), "x-fill");
}
if (priv->y_fill != y_fill)
{
priv->y_fill = y_fill;
changed = TRUE;
g_object_notify (G_OBJECT (bin), "y-fill");
}
if (changed)
clutter_actor_queue_relayout (CLUTTER_ACTOR (bin));
g_object_thaw_notify (G_OBJECT (bin));
}
/**
* nbtk_bin_get_fill:
* @bin: a #NbtkBin
* @x_fill: (out): return location for the horizontal fill, or %NULL
* @y_fill: (out): return location for the vertical fill, or %NULL
*
* Retrieves the horizontal and vertical fill settings
*/
void
nbtk_bin_get_fill (NbtkBin *bin,
gboolean *x_fill,
gboolean *y_fill)
{
g_return_if_fail (NBTK_IS_BIN (bin));
if (x_fill)
*x_fill = bin->priv->x_fill;
if (y_fill)
*y_fill = bin->priv->y_fill;
}

92
src/nbtk/nbtk-bin.h Normal file
View File

@ -0,0 +1,92 @@
/*
* nbtk-bin.h: Basic container actor
*
* Copyright 2009, 2008 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
* Written by: Emmanuele Bassi <ebassi@linux.intel.com>
*
*/
#if !defined(NBTK_H_INSIDE) && !defined(NBTK_COMPILATION)
#error "Only <nbtk/nbtk.h> can be included directly.h"
#endif
#ifndef __NBTK_BIN_H__
#define __NBTK_BIN_H__
#include <nbtk/nbtk-types.h>
#include <nbtk/nbtk-widget.h>
G_BEGIN_DECLS
#define NBTK_TYPE_BIN (nbtk_bin_get_type ())
#define NBTK_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NBTK_TYPE_BIN, NbtkBin))
#define NBTK_IS_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NBTK_TYPE_BIN))
#define NBTK_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NBTK_TYPE_BIN, NbtkBinClass))
#define NBTK_IS_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NBTK_TYPE_BIN))
#define NBTK_BIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NBTK_TYPE_BIN, NbtkBinClass))
typedef struct _NbtkBin NbtkBin;
typedef struct _NbtkBinPrivate NbtkBinPrivate;
typedef struct _NbtkBinClass NbtkBinClass;
/**
* NbtkBin:
*
* The #NbtkBin struct contains only private data
*/
struct _NbtkBin
{
/*< private >*/
NbtkWidget parent_instance;
NbtkBinPrivate *priv;
};
/**
* NbtkBinClass:
*
* The #NbtkBinClass struct contains only private data
*/
struct _NbtkBinClass
{
/*< private >*/
NbtkWidgetClass parent_class;
};
GType nbtk_bin_get_type (void) G_GNUC_CONST;
NbtkWidget *nbtk_bin_new (void);
void nbtk_bin_set_child (NbtkBin *bin,
ClutterActor *child);
ClutterActor *nbtk_bin_get_child (NbtkBin *bin);
void nbtk_bin_set_alignment (NbtkBin *bin,
NbtkAlignment x_align,
NbtkAlignment y_align);
void nbtk_bin_get_alignment (NbtkBin *bin,
NbtkAlignment *x_align,
NbtkAlignment *y_align);
void nbtk_bin_set_fill (NbtkBin *bin,
gboolean x_fill,
gboolean y_fill);
void nbtk_bin_get_fill (NbtkBin *bin,
gboolean *x_fill,
gboolean *y_fill);
G_END_DECLS
#endif /* __NBTK_BIN_H__ */

View File

@ -0,0 +1,176 @@
/*
* nbtk-box-layout-child.c: box layout child actor
*
* Copyright 2009 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* Written by: Thomas Wood <thomas.wood@intel.com>
*/
#include "nbtk-box-layout-child.h"
#include "nbtk-private.h"
G_DEFINE_TYPE (NbtkBoxLayoutChild, nbtk_box_layout_child, CLUTTER_TYPE_CHILD_META)
#define BOX_LAYOUT_CHILD_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), NBTK_TYPE_BOX_LAYOUT_CHILD, NbtkBoxLayoutChildPrivate))
enum
{
PROP_0,
PROP_EXPAND,
PROP_X_FILL,
PROP_Y_FILL,
PROP_X_ALIGN,
PROP_Y_ALIGN
};
static void
nbtk_box_layout_child_get_property (GObject *object, guint property_id,
GValue *value, GParamSpec *pspec)
{
NbtkBoxLayoutChild *child = NBTK_BOX_LAYOUT_CHILD (object);
switch (property_id)
{
case PROP_EXPAND:
g_value_set_boolean (value, child->expand);
break;
case PROP_X_FILL:
g_value_set_boolean (value, child->x_fill);
break;
case PROP_Y_FILL:
g_value_set_boolean (value, child->y_fill);
break;
case PROP_X_ALIGN:
g_value_set_enum (value, child->x_align);
break;
case PROP_Y_ALIGN:
g_value_set_enum (value, child->y_align);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
nbtk_box_layout_child_set_property (GObject *object, guint property_id,
const GValue *value, GParamSpec *pspec)
{
NbtkBoxLayoutChild *child = NBTK_BOX_LAYOUT_CHILD (object);
NbtkBoxLayout *box = NBTK_BOX_LAYOUT (CLUTTER_CHILD_META (object)->container);
switch (property_id)
{
case PROP_EXPAND:
child->expand = g_value_get_boolean (value);
break;
case PROP_X_FILL:
child->x_fill = g_value_get_boolean (value);
break;
case PROP_Y_FILL:
child->y_fill = g_value_get_boolean (value);
break;
case PROP_X_ALIGN:
child->x_align = g_value_get_enum (value);
break;
case PROP_Y_ALIGN:
child->y_align = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
clutter_actor_queue_relayout ((ClutterActor*) box);
}
static void
nbtk_box_layout_child_dispose (GObject *object)
{
G_OBJECT_CLASS (nbtk_box_layout_child_parent_class)->dispose (object);
}
static void
nbtk_box_layout_child_finalize (GObject *object)
{
G_OBJECT_CLASS (nbtk_box_layout_child_parent_class)->finalize (object);
}
static void
nbtk_box_layout_child_class_init (NbtkBoxLayoutChildClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
object_class->get_property = nbtk_box_layout_child_get_property;
object_class->set_property = nbtk_box_layout_child_set_property;
object_class->dispose = nbtk_box_layout_child_dispose;
object_class->finalize = nbtk_box_layout_child_finalize;
pspec = g_param_spec_boolean ("expand", "Expand",
"Allocate the child extra space",
FALSE,
NBTK_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_EXPAND, pspec);
pspec = g_param_spec_boolean ("x-fill", "x-fill",
"Whether the child should receive priority "
"when the container is allocating spare space "
"on the horizontal axis",
TRUE,
NBTK_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_X_FILL, pspec);
pspec = g_param_spec_boolean ("y-fill", "y-fill",
"Whether the child should receive priority "
"when the container is allocating spare space "
"on the vertical axis",
TRUE,
NBTK_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_Y_FILL, pspec);
pspec = g_param_spec_enum ("x-align",
"X Alignment",
"X alignment of the widget within the cell",
NBTK_TYPE_ALIGN,
NBTK_ALIGN_MIDDLE,
NBTK_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_X_ALIGN, pspec);
pspec = g_param_spec_enum ("y-align",
"Y Alignment",
"Y alignment of the widget within the cell",
NBTK_TYPE_ALIGN,
NBTK_ALIGN_MIDDLE,
NBTK_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_Y_ALIGN, pspec);
}
static void
nbtk_box_layout_child_init (NbtkBoxLayoutChild *self)
{
self->expand = FALSE;
self->x_fill = TRUE;
self->y_fill = TRUE;
self->x_align = NBTK_ALIGN_CENTER;
self->y_align = NBTK_ALIGN_CENTER;
}

View File

@ -0,0 +1,84 @@
/*
* nbtk-box-layout-child.h: box layout child actor
*
* Copyright 2009 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* Written by: Thomas Wood <thomas.wood@intel.com>
*/
#ifndef _NBTK_BOX_LAYOUT_CHILD_H
#define _NBTK_BOX_LAYOUT_CHILD_H
#include <clutter/clutter.h>
#include "nbtk-enum-types.h"
#include "nbtk-box-layout.h"
G_BEGIN_DECLS
#define NBTK_TYPE_BOX_LAYOUT_CHILD nbtk_box_layout_child_get_type()
#define NBTK_BOX_LAYOUT_CHILD(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
NBTK_TYPE_BOX_LAYOUT_CHILD, NbtkBoxLayoutChild))
#define NBTK_BOX_LAYOUT_CHILD_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), \
NBTK_TYPE_BOX_LAYOUT_CHILD, NbtkBoxLayoutChildClass))
#define NBTK_IS_BOX_LAYOUT_CHILD(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
NBTK_TYPE_BOX_LAYOUT_CHILD))
#define NBTK_IS_BOX_LAYOUT_CHILD_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
NBTK_TYPE_BOX_LAYOUT_CHILD))
#define NBTK_BOX_LAYOUT_CHILD_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
NBTK_TYPE_BOX_LAYOUT_CHILD, NbtkBoxLayoutChildClass))
typedef struct _NbtkBoxLayoutChild NbtkBoxLayoutChild;
typedef struct _NbtkBoxLayoutChildClass NbtkBoxLayoutChildClass;
typedef struct _NbtkBoxLayoutChildPrivate NbtkBoxLayoutChildPrivate;
/**
* NbtkBoxLayoutChild:
*
* The contents of this structure are private and should only be accessed
* through the public API.
*/
struct _NbtkBoxLayoutChild
{
/*< private >*/
ClutterChildMeta parent;
gboolean expand;
gboolean x_fill : 1;
gboolean y_fill : 1;
NbtkAlign x_align;
NbtkAlign y_align;
};
struct _NbtkBoxLayoutChildClass
{
ClutterChildMetaClass parent_class;
};
GType nbtk_box_layout_child_get_type (void);
G_END_DECLS
#endif /* _NBTK_BOX_LAYOUT_CHILD_H */

1252
src/nbtk/nbtk-box-layout.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,91 @@
/*
* nbtk-box-layout.h: box layout actor
*
* Copyright 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* Written by: Thomas Wood <thomas.wood@intel.com>
*
*/
#ifndef _NBTK_BOX_LAYOUT_H
#define _NBTK_BOX_LAYOUT_H
#include <nbtk/nbtk-widget.h>
G_BEGIN_DECLS
#define NBTK_TYPE_BOX_LAYOUT nbtk_box_layout_get_type()
#define NBTK_BOX_LAYOUT(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
NBTK_TYPE_BOX_LAYOUT, NbtkBoxLayout))
#define NBTK_BOX_LAYOUT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), \
NBTK_TYPE_BOX_LAYOUT, NbtkBoxLayoutClass))
#define NBTK_IS_BOX_LAYOUT(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
NBTK_TYPE_BOX_LAYOUT))
#define NBTK_IS_BOX_LAYOUT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
NBTK_TYPE_BOX_LAYOUT))
#define NBTK_BOX_LAYOUT_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
NBTK_TYPE_BOX_LAYOUT, NbtkBoxLayoutClass))
typedef struct _NbtkBoxLayout NbtkBoxLayout;
typedef struct _NbtkBoxLayoutClass NbtkBoxLayoutClass;
typedef struct _NbtkBoxLayoutPrivate NbtkBoxLayoutPrivate;
/**
* NbtkBoxLayout:
*
* The contents of this structure are private and should only be accessed
* through the public API.
*/
struct _NbtkBoxLayout
{
/*< private >*/
NbtkWidget parent;
NbtkBoxLayoutPrivate *priv;
};
struct _NbtkBoxLayoutClass
{
NbtkWidgetClass parent_class;
};
GType nbtk_box_layout_get_type (void);
NbtkWidget *nbtk_box_layout_new (void);
void nbtk_box_layout_set_vertical (NbtkBoxLayout *box, gboolean vertical);
gboolean nbtk_box_layout_get_vertical (NbtkBoxLayout *box);
void nbtk_box_layout_set_pack_start (NbtkBoxLayout *box, gboolean pack_start);
gboolean nbtk_box_layout_get_pack_start (NbtkBoxLayout *box);
void nbtk_box_layout_set_spacing (NbtkBoxLayout *box, guint spacing);
guint nbtk_box_layout_get_spacing (NbtkBoxLayout *box);
G_END_DECLS
#endif /* _NBTK_BOX_LAYOUT_H */

690
src/nbtk/nbtk-button.c Normal file
View File

@ -0,0 +1,690 @@
/*-button.c: Plain button actor
* Copyright 2007 OpenedHand
* Copyright , 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* Written by: Emmanuele Bassi <ebassi@openedhand.com>
* Thomas Wood <thomas@linux.intel.com>
*
*/
/**
* SECTION:nbtk-button
* @short_description: Button widget
*
* A button widget with support for either a text label or icon, toggle mode
* and transitions effects between states.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <clutter/clutter.h>
#include "nbtk-button.h"
#include "nbtk-marshal.h"
#include "nbtk-texture-frame.h"
#include "nbtk-texture-cache.h"
#include "nbtk-private.h"
enum
{
PROP_0,
PROP_LABEL,
PROP_TOGGLE,
PROP_ACTIVE,
PROP_TRANSITION
};
enum
{
CLICKED,
LAST_SIGNAL
};
#define NBTK_BUTTON_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), NBTK_TYPE_BUTTON, NbtkButtonPrivate))
struct _NbtkButtonPrivate
{
gchar *text;
ClutterActor *old_bg;
gboolean old_bg_parented; /* TRUE if we have adopted old_bg */
guint8 old_opacity;
guint is_pressed : 1;
guint is_hover : 1;
guint is_checked : 1;
guint is_toggle : 1;
gint transition_duration;
ClutterAnimation *animation;
gint spacing;
};
static guint button_signals[LAST_SIGNAL] = { 0, };
G_DEFINE_TYPE (NbtkButton, nbtk_button, NBTK_TYPE_BIN);
static void
nbtk_button_update_label_style (NbtkButton *button)
{
ClutterActor *label;
ShellThemeNode *theme_node;
ClutterColor color;
const PangoFontDescription *font;
gchar *font_string = NULL;
label = nbtk_bin_get_child ((NbtkBin*) button);
/* check the child is really a label */
if (!CLUTTER_IS_TEXT (label))
return;
theme_node = nbtk_widget_get_theme_node (NBTK_WIDGET (button));
shell_theme_node_get_foreground_color (theme_node, &color);
clutter_text_set_color (CLUTTER_TEXT (label), &color);
font = shell_theme_node_get_font (theme_node);
font_string = pango_font_description_to_string (font);
clutter_text_set_font_name (CLUTTER_TEXT (label), font_string);
g_free (font_string);
}
static void
nbtk_button_dispose_old_bg (NbtkButton *button)
{
NbtkButtonPrivate *priv = button->priv;
if (priv->old_bg)
{
if (priv->old_bg_parented)
{
clutter_actor_unparent (priv->old_bg);
priv->old_bg_parented = FALSE;
}
g_object_unref (priv->old_bg);
priv->old_bg = NULL;
}
}
static void
nbtk_animation_completed (ClutterAnimation *animation,
NbtkButton *button)
{
nbtk_button_dispose_old_bg (button);
}
static void
nbtk_button_style_changed (NbtkWidget *widget)
{
NbtkButton *button = NBTK_BUTTON (widget);
NbtkButtonPrivate *priv = button->priv;
NbtkButtonClass *button_class = NBTK_BUTTON_GET_CLASS (button);
ShellThemeNode *theme_node = nbtk_widget_get_theme_node (NBTK_WIDGET (button));
ClutterActor *bg_image;
double spacing;
nbtk_button_dispose_old_bg (button);
bg_image = nbtk_widget_get_border_image ((NbtkWidget*) button);
if (bg_image)
button->priv->old_bg = g_object_ref (bg_image);
NBTK_WIDGET_CLASS (nbtk_button_parent_class)->style_changed (widget);
spacing = 6;
shell_theme_node_get_length (theme_node, "border-spacing", FALSE, &spacing);
priv->spacing = round (spacing);
/* update the label styling */
nbtk_button_update_label_style (button);
/* run a transition if applicable */
if (button_class->transition)
{
button_class->transition (button, priv->old_bg);
}
else
{
if (priv->old_bg &&
(!nbtk_widget_get_style_pseudo_class (widget)))
{
ClutterAnimation *animation;
if (!clutter_actor_get_parent (priv->old_bg))
{
clutter_actor_set_parent (priv->old_bg, (ClutterActor*) widget);
priv->old_bg_parented = TRUE;
}
if (priv->transition_duration > 0)
{
animation = clutter_actor_animate (priv->old_bg,
CLUTTER_LINEAR,
priv->transition_duration,
"opacity", 0,
NULL);
g_signal_connect (animation, "completed",
G_CALLBACK (nbtk_animation_completed), button);
}
else
{
nbtk_button_dispose_old_bg (button);
}
}
}
}
static void
nbtk_button_real_pressed (NbtkButton *button)
{
nbtk_widget_set_style_pseudo_class ((NbtkWidget*) button, "active");
}
static void
nbtk_button_real_released (NbtkButton *button)
{
NbtkButtonPrivate *priv = button->priv;
if (priv->is_checked)
nbtk_widget_set_style_pseudo_class ((NbtkWidget*) button, "checked");
else if (!priv->is_hover)
nbtk_widget_set_style_pseudo_class ((NbtkWidget*) button, NULL);
else
nbtk_widget_set_style_pseudo_class ((NbtkWidget*) button, "hover");
}
static gboolean
nbtk_button_button_press (ClutterActor *actor,
ClutterButtonEvent *event)
{
nbtk_widget_hide_tooltip (NBTK_WIDGET (actor));
if (event->button == 1)
{
NbtkButton *button = NBTK_BUTTON (actor);
NbtkButtonClass *klass = NBTK_BUTTON_GET_CLASS (button);
button->priv->is_pressed = TRUE;
clutter_grab_pointer (actor);
if (klass->pressed)
klass->pressed (button);
return TRUE;
}
return FALSE;
}
static gboolean
nbtk_button_button_release (ClutterActor *actor,
ClutterButtonEvent *event)
{
if (event->button == 1)
{
NbtkButton *button = NBTK_BUTTON (actor);
NbtkButtonClass *klass = NBTK_BUTTON_GET_CLASS (button);
if (!button->priv->is_pressed)
return FALSE;
clutter_ungrab_pointer ();
if (button->priv->is_toggle)
{
nbtk_button_set_checked (button, !button->priv->is_checked);
}
button->priv->is_pressed = FALSE;
if (klass->released)
klass->released (button);
g_signal_emit (button, button_signals[CLICKED], 0);
return TRUE;
}
return FALSE;
}
static gboolean
nbtk_button_enter (ClutterActor *actor,
ClutterCrossingEvent *event)
{
NbtkButton *button = NBTK_BUTTON (actor);
if (!button->priv->is_checked)
nbtk_widget_set_style_pseudo_class ((NbtkWidget*) button, "hover");
button->priv->is_hover = 1;
return CLUTTER_ACTOR_CLASS (nbtk_button_parent_class)->enter_event (actor, event);
}
static gboolean
nbtk_button_leave (ClutterActor *actor,
ClutterCrossingEvent *event)
{
NbtkButton *button = NBTK_BUTTON (actor);
button->priv->is_hover = 0;
if (button->priv->is_pressed)
{
NbtkButtonClass *klass = NBTK_BUTTON_GET_CLASS (button);
clutter_ungrab_pointer ();
button->priv->is_pressed = FALSE;
if (klass->released)
klass->released (button);
}
if (button->priv->is_checked)
nbtk_widget_set_style_pseudo_class ((NbtkWidget*) button, "checked");
else
nbtk_widget_set_style_pseudo_class ((NbtkWidget*) button, NULL);
return CLUTTER_ACTOR_CLASS (nbtk_button_parent_class)->leave_event (actor, event);
}
static void
nbtk_button_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
NbtkButton *button = NBTK_BUTTON (gobject);
NbtkButtonPrivate *priv = NBTK_BUTTON (gobject)->priv;
switch (prop_id)
{
case PROP_LABEL:
nbtk_button_set_label (button, g_value_get_string (value));
break;
case PROP_TOGGLE:
nbtk_button_set_toggle_mode (button, g_value_get_boolean (value));
break;
case PROP_ACTIVE:
nbtk_button_set_checked (button, g_value_get_boolean (value));
break;
case PROP_TRANSITION:
priv->transition_duration = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
nbtk_button_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
NbtkButtonPrivate *priv = NBTK_BUTTON (gobject)->priv;
switch (prop_id)
{
case PROP_LABEL:
g_value_set_string (value, priv->text);
break;
case PROP_TOGGLE:
g_value_set_boolean (value, priv->is_toggle);
break;
case PROP_ACTIVE:
g_value_set_boolean (value, priv->is_checked);
break;
case PROP_TRANSITION:
g_value_set_int (value, priv->transition_duration);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
nbtk_button_finalize (GObject *gobject)
{
NbtkButtonPrivate *priv = NBTK_BUTTON (gobject)->priv;
g_free (priv->text);
G_OBJECT_CLASS (nbtk_button_parent_class)->finalize (gobject);
}
static void
nbtk_button_dispose (GObject *gobject)
{
nbtk_button_dispose_old_bg (NBTK_BUTTON (gobject));
G_OBJECT_CLASS (nbtk_button_parent_class)->dispose (gobject);
}
static void
nbtk_button_map (ClutterActor *self)
{
NbtkButtonPrivate *priv = NBTK_BUTTON (self)->priv;
CLUTTER_ACTOR_CLASS (nbtk_button_parent_class)->map (self);
if (priv->old_bg && priv->old_bg_parented)
clutter_actor_map (priv->old_bg);
}
static void
nbtk_button_unmap (ClutterActor *self)
{
NbtkButtonPrivate *priv = NBTK_BUTTON (self)->priv;
CLUTTER_ACTOR_CLASS (nbtk_button_parent_class)->unmap (self);
if (priv->old_bg && priv->old_bg_parented)
clutter_actor_unmap (priv->old_bg);
}
static void
nbtk_button_draw_background (NbtkWidget *widget)
{
NbtkButtonPrivate *priv;
NBTK_WIDGET_CLASS (nbtk_button_parent_class)->draw_background (widget);
priv = NBTK_BUTTON (widget)->priv;
if (priv->old_bg && priv->old_bg_parented)
clutter_actor_paint (priv->old_bg);
}
static void
nbtk_button_class_init (NbtkButtonClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
NbtkWidgetClass *widget_class = NBTK_WIDGET_CLASS (klass);
GParamSpec *pspec;
g_type_class_add_private (klass, sizeof (NbtkButtonPrivate));
klass->pressed = nbtk_button_real_pressed;
klass->released = nbtk_button_real_released;
gobject_class->set_property = nbtk_button_set_property;
gobject_class->get_property = nbtk_button_get_property;
gobject_class->dispose = nbtk_button_dispose;
gobject_class->finalize = nbtk_button_finalize;
actor_class->button_press_event = nbtk_button_button_press;
actor_class->button_release_event = nbtk_button_button_release;
actor_class->enter_event = nbtk_button_enter;
actor_class->leave_event = nbtk_button_leave;
actor_class->map = nbtk_button_map;
actor_class->unmap = nbtk_button_unmap;
widget_class->draw_background = nbtk_button_draw_background;
widget_class->style_changed = nbtk_button_style_changed;
pspec = g_param_spec_string ("label",
"Label",
"Label of the button",
NULL, G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_LABEL, pspec);
pspec = g_param_spec_boolean ("toggle-mode",
"Toggle Mode",
"Enable or disable toggling",
FALSE, G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_TOGGLE, pspec);
pspec = g_param_spec_boolean ("checked",
"Checked",
"Indicates if a toggle button is \"on\""
" or \"off\"",
FALSE, G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_ACTIVE, pspec);
pspec = g_param_spec_int ("transition-duration",
"Transition Duration",
"Duration of the state transition effect",
0, G_MAXINT, 120, G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_TRANSITION, pspec);
/**
* NbtkButton::clicked:
* @button: the object that received the signal
*
* Emitted when the user activates the button, either with a mouse press and
* release or with the keyboard.
*/
button_signals[CLICKED] =
g_signal_new ("clicked",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NbtkButtonClass, clicked),
NULL, NULL,
_nbtk_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static void
nbtk_button_init (NbtkButton *button)
{
button->priv = NBTK_BUTTON_GET_PRIVATE (button);
button->priv->transition_duration = 120;
button->priv->spacing = 6;
clutter_actor_set_reactive ((ClutterActor *) button, TRUE);
}
/**
* nbtk_button_new:
*
* Create a new button
*
* Returns: a new #NbtkButton
*/
NbtkWidget *
nbtk_button_new (void)
{
return g_object_new (NBTK_TYPE_BUTTON, NULL);
}
/**
* nbtk_button_new_with_label:
* @text: text to set the label to
*
* Create a new #NbtkButton with the specified label
*
* Returns: a new #NbtkButton
*/
NbtkWidget *
nbtk_button_new_with_label (const gchar *text)
{
return g_object_new (NBTK_TYPE_BUTTON, "label", text, NULL);
}
/**
* nbtk_button_get_label:
* @button: a #NbtkButton
*
* Get the text displayed on the button
*
* Returns: the text for the button. This must not be freed by the application
*/
G_CONST_RETURN gchar *
nbtk_button_get_label (NbtkButton *button)
{
g_return_val_if_fail (NBTK_IS_BUTTON (button), NULL);
return button->priv->text;
}
/**
* nbtk_button_set_label:
* @button: a #Nbtkbutton
* @text: text to set the label to
*
* Sets the text displayed on the button
*/
void
nbtk_button_set_label (NbtkButton *button,
const gchar *text)
{
NbtkButtonPrivate *priv;
ClutterActor *label;
g_return_if_fail (NBTK_IS_BUTTON (button));
priv = button->priv;
g_free (priv->text);
if (text)
priv->text = g_strdup (text);
else
priv->text = g_strdup ("");
label = nbtk_bin_get_child ((NbtkBin*) button);
if (label && CLUTTER_IS_TEXT (label))
{
clutter_text_set_text (CLUTTER_TEXT (label), priv->text);
}
else
{
label = g_object_new (CLUTTER_TYPE_TEXT,
"text", priv->text,
"line-alignment", PANGO_ALIGN_CENTER,
"ellipsize", PANGO_ELLIPSIZE_END,
"use-markup", TRUE,
NULL);
nbtk_bin_set_child ((NbtkBin*) button, label);
}
/* Fake a style change so that we reset the style properties on the label */
nbtk_widget_style_changed (NBTK_WIDGET (button));
g_object_notify (G_OBJECT (button), "label");
}
/**
* nbtk_button_get_toggle_mode:
* @button: a #NbtkButton
*
* Get the toggle mode status of the button.
*
* Returns: #TRUE if toggle mode is set, otherwise #FALSE
*/
gboolean
nbtk_button_get_toggle_mode (NbtkButton *button)
{
g_return_val_if_fail (NBTK_IS_BUTTON (button), FALSE);
return button->priv->is_toggle;
}
/**
* nbtk_button_set_toggle_mode:
* @button: a #Nbtkbutton
* @toggle: #TRUE or #FALSE
*
* Enables or disables toggle mode for the button. In toggle mode, the active
* state will be "toggled" when the user clicks the button.
*/
void
nbtk_button_set_toggle_mode (NbtkButton *button,
gboolean toggle)
{
g_return_if_fail (NBTK_IS_BUTTON (button));
button->priv->is_toggle = toggle;
g_object_notify (G_OBJECT (button), "toggle-mode");
}
/**
* nbtk_button_get_checked:
* @button: a #NbtkButton
*
* Get the state of the button that is in toggle mode.
*
* Returns: #TRUE if the button is checked, or #FALSE if not
*/
gboolean
nbtk_button_get_checked (NbtkButton *button)
{
g_return_val_if_fail (NBTK_IS_BUTTON (button), FALSE);
return button->priv->is_checked;
}
/**
* nbtk_button_set_checked:
* @button: a #Nbtkbutton
* @checked: #TRUE or #FALSE
*
* Sets the pressed state of the button. This is only really useful if the
* button has #toggle-mode mode set to #TRUE.
*/
void
nbtk_button_set_checked (NbtkButton *button,
gboolean checked)
{
g_return_if_fail (NBTK_IS_BUTTON (button));
if (button->priv->is_checked != checked)
{
button->priv->is_checked = checked;
if (checked)
nbtk_widget_set_style_pseudo_class ((NbtkWidget*) button, "checked");
else
if (button->priv->is_hover)
nbtk_widget_set_style_pseudo_class ((NbtkWidget*) button, "hover");
else
nbtk_widget_set_style_pseudo_class ((NbtkWidget*) button, NULL);
}
g_object_notify (G_OBJECT (button), "checked");
}

90
src/nbtk/nbtk-button.h Normal file
View File

@ -0,0 +1,90 @@
/*
* nbtk-button.h: Plain button actor
*
* Copyright 2007 OpenedHand
* Copyright 2008, 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
* Written by: Emmanuele Bassi <ebassi@openedhand.com>
* Thomas Wood <thomas@linux.intel.com>
*
*/
#if !defined(NBTK_H_INSIDE) && !defined(NBTK_COMPILATION)
#error "Only <nbtk/nbtk.h> can be included directly.h"
#endif
#ifndef __NBTK_BUTTON_H__
#define __NBTK_BUTTON_H__
G_BEGIN_DECLS
#include <nbtk/nbtk-bin.h>
#define NBTK_TYPE_BUTTON (nbtk_button_get_type ())
#define NBTK_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NBTK_TYPE_BUTTON, NbtkButton))
#define NBTK_IS_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NBTK_TYPE_BUTTON))
#define NBTK_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NBTK_TYPE_BUTTON, NbtkButtonClass))
#define NBTK_IS_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NBTK_TYPE_BUTTON))
#define NBTK_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NBTK_TYPE_BUTTON, NbtkButtonClass))
typedef struct _NbtkButton NbtkButton;
typedef struct _NbtkButtonPrivate NbtkButtonPrivate;
typedef struct _NbtkButtonClass NbtkButtonClass;
/**
* NbtkButton:
*
* The contents of this structure is private and should only be accessed using
* the provided API.
*/
struct _NbtkButton
{
/*< private >*/
NbtkBin parent_instance;
NbtkButtonPrivate *priv;
};
struct _NbtkButtonClass
{
NbtkBinClass parent_class;
/* vfuncs, not signals */
void (* pressed) (NbtkButton *button);
void (* released) (NbtkButton *button);
void (* transition) (NbtkButton *button, ClutterActor *old_bg);
/* signals */
void (* clicked) (NbtkButton *button);
};
GType nbtk_button_get_type (void) G_GNUC_CONST;
NbtkWidget * nbtk_button_new (void);
NbtkWidget * nbtk_button_new_with_label (const gchar *text);
G_CONST_RETURN gchar *nbtk_button_get_label (NbtkButton *button);
void nbtk_button_set_label (NbtkButton *button,
const gchar *text);
void nbtk_button_set_toggle_mode (NbtkButton *button, gboolean toggle);
gboolean nbtk_button_get_toggle_mode (NbtkButton *button);
void nbtk_button_set_checked (NbtkButton *button, gboolean checked);
gboolean nbtk_button_get_checked (NbtkButton *button);
G_END_DECLS
#endif /* __NBTK_BUTTON_H__ */

367
src/nbtk/nbtk-clipboard.c Normal file
View File

@ -0,0 +1,367 @@
/*
* nbtk-clipboard.c: clipboard object
*
* Copyright 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* Written by: Thomas Wood <thomas.wood@intel.com>
*
*/
#include "nbtk-clipboard.h"
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <clutter/x11/clutter-x11.h>
#include <string.h>
G_DEFINE_TYPE (NbtkClipboard, nbtk_clipboard, G_TYPE_OBJECT)
#define CLIPBOARD_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), NBTK_TYPE_CLIPBOARD, NbtkClipboardPrivate))
struct _NbtkClipboardPrivate
{
Window clipboard_window;
gchar *clipboard_text;
Atom *supported_targets;
gint n_targets;
};
typedef struct _EventFilterData EventFilterData;
struct _EventFilterData
{
NbtkClipboard *clipboard;
NbtkClipboardCallbackFunc callback;
gpointer user_data;
};
static Atom __atom_clip = None;
static Atom __utf8_string = None;
static Atom __atom_targets = None;
static void
nbtk_clipboard_get_property (GObject *object, guint property_id,
GValue *value, GParamSpec *pspec)
{
switch (property_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
nbtk_clipboard_set_property (GObject *object, guint property_id,
const GValue *value, GParamSpec *pspec)
{
switch (property_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
nbtk_clipboard_dispose (GObject *object)
{
G_OBJECT_CLASS (nbtk_clipboard_parent_class)->dispose (object);
}
static void
nbtk_clipboard_finalize (GObject *object)
{
NbtkClipboardPrivate *priv = ((NbtkClipboard *) object)->priv;
g_free (priv->clipboard_text);
priv->clipboard_text = NULL;
g_free (priv->supported_targets);
priv->supported_targets = NULL;
priv->n_targets = 0;
G_OBJECT_CLASS (nbtk_clipboard_parent_class)->finalize (object);
}
static ClutterX11FilterReturn
nbtk_clipboard_provider (XEvent *xev,
ClutterEvent *cev,
NbtkClipboard *clipboard)
{
XSelectionEvent notify_event;
XSelectionRequestEvent *req_event;
if (xev->type != SelectionRequest)
return CLUTTER_X11_FILTER_CONTINUE;
req_event = &xev->xselectionrequest;
clutter_x11_trap_x_errors ();
if (req_event->target == __atom_targets)
{
XChangeProperty (req_event->display,
req_event->requestor,
req_event->property,
XA_ATOM,
32,
PropModeReplace,
(guchar*) clipboard->priv->supported_targets,
clipboard->priv->n_targets);
}
else
{
XChangeProperty (req_event->display,
req_event->requestor,
req_event->property,
req_event->target,
8,
PropModeReplace,
(guchar*) clipboard->priv->clipboard_text,
strlen (clipboard->priv->clipboard_text));
}
notify_event.type = SelectionNotify;
notify_event.display = req_event->display;
notify_event.requestor = req_event->requestor;
notify_event.selection = req_event->selection;
notify_event.target = req_event->target;
notify_event.time = req_event->time;
if (req_event->property == None)
notify_event.property = req_event->target;
else
notify_event.property = req_event->property;
/* notify the requestor that they have a copy of the selection */
XSendEvent (req_event->display, req_event->requestor, False, 0,
(XEvent *) &notify_event);
/* Make it happen non async */
XSync (clutter_x11_get_default_display(), FALSE);
clutter_x11_untrap_x_errors (); /* FIXME: Warn here on fail ? */
return CLUTTER_X11_FILTER_REMOVE;
}
static void
nbtk_clipboard_class_init (NbtkClipboardClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (NbtkClipboardPrivate));
object_class->get_property = nbtk_clipboard_get_property;
object_class->set_property = nbtk_clipboard_set_property;
object_class->dispose = nbtk_clipboard_dispose;
object_class->finalize = nbtk_clipboard_finalize;
}
static void
nbtk_clipboard_init (NbtkClipboard *self)
{
Display *dpy;
NbtkClipboardPrivate *priv;
priv = self->priv = CLIPBOARD_PRIVATE (self);
priv->clipboard_window =
XCreateSimpleWindow (clutter_x11_get_default_display (),
clutter_x11_get_root_window (),
-1, -1, 1, 1, 0, 0, 0);
dpy = clutter_x11_get_default_display ();
/* Only create once */
if (__atom_clip == None)
__atom_clip = XInternAtom (dpy, "CLIPBOARD", 0);
if (__utf8_string == None)
__utf8_string = XInternAtom (dpy, "UTF8_STRING", 0);
if (__atom_targets == None)
__atom_targets = XInternAtom (dpy, "TARGETS", 0);
priv->n_targets = 2;
priv->supported_targets = g_new (Atom, priv->n_targets);
priv->supported_targets[0] = __utf8_string;
priv->supported_targets[1] = __atom_targets;
clutter_x11_add_filter ((ClutterX11FilterFunc) nbtk_clipboard_provider,
self);
}
static ClutterX11FilterReturn
nbtk_clipboard_x11_event_filter (XEvent *xev,
ClutterEvent *cev,
EventFilterData *filter_data)
{
Atom actual_type;
int actual_format, result;
unsigned long nitems, bytes_after;
unsigned char *data = NULL;
if(xev->type != SelectionNotify)
return CLUTTER_X11_FILTER_CONTINUE;
if (xev->xselection.property == None)
{
/* clipboard empty */
filter_data->callback (filter_data->clipboard,
NULL,
filter_data->user_data);
clutter_x11_remove_filter ((ClutterX11FilterFunc) nbtk_clipboard_x11_event_filter,
filter_data);
g_free (filter_data);
return CLUTTER_X11_FILTER_REMOVE;
}
clutter_x11_trap_x_errors ();
result = XGetWindowProperty (xev->xselection.display,
xev->xselection.requestor,
xev->xselection.property,
0L, G_MAXINT,
True,
AnyPropertyType,
&actual_type,
&actual_format,
&nitems,
&bytes_after,
&data);
if (clutter_x11_untrap_x_errors () || result != Success)
{
/* FIXME: handle failure better */
g_warning ("Clipboard: prop retrival failed");
}
filter_data->callback (filter_data->clipboard, (char*) data,
filter_data->user_data);
clutter_x11_remove_filter
((ClutterX11FilterFunc) nbtk_clipboard_x11_event_filter,
filter_data);
g_free (filter_data);
if (data)
XFree (data);
return CLUTTER_X11_FILTER_REMOVE;
}
/**
* nbtk_clipboard_get_default:
*
* Get the global #NbtkClipboard object that represents the clipboard.
*
* Returns: (transfer none): a #NbtkClipboard owned by Nbtk and must not be
* unrefferenced or freed.
*/
NbtkClipboard*
nbtk_clipboard_get_default (void)
{
static NbtkClipboard *default_clipboard = NULL;
if (!default_clipboard)
{
default_clipboard = g_object_new (NBTK_TYPE_CLIPBOARD, NULL);
}
return default_clipboard;
}
/**
* nbtk_clipboard_get_text:
* @clipboard: A #NbtkCliboard
* @callback: function to be called when the text is retreived
* @user_data: data to be passed to the callback
*
* Request the data from the clipboard in text form. @callback is executed
* when the data is retreived.
*
*/
void
nbtk_clipboard_get_text (NbtkClipboard *clipboard,
NbtkClipboardCallbackFunc callback,
gpointer user_data)
{
EventFilterData *data;
Display *dpy;
g_return_if_fail (NBTK_IS_CLIPBOARD (clipboard));
g_return_if_fail (callback != NULL);
data = g_new0 (EventFilterData, 1);
data->clipboard = clipboard;
data->callback = callback;
data->user_data = user_data;
clutter_x11_add_filter ((ClutterX11FilterFunc)nbtk_clipboard_x11_event_filter,
data);
dpy = clutter_x11_get_default_display ();
clutter_x11_trap_x_errors (); /* safety on */
XConvertSelection (dpy,
__atom_clip,
__utf8_string, __utf8_string,
clipboard->priv->clipboard_window,
CurrentTime);
clutter_x11_untrap_x_errors ();
}
/**
* nbtk_clipboard_set_text:
* @clipboard: A #NbtkClipboard
* @text: text to copy to the clipboard
*
* Sets text as the current contents of the clipboard.
*
*/
void
nbtk_clipboard_set_text (NbtkClipboard *clipboard,
const gchar *text)
{
NbtkClipboardPrivate *priv;
Display *dpy;
g_return_if_fail (NBTK_IS_CLIPBOARD (clipboard));
g_return_if_fail (text != NULL);
priv = clipboard->priv;
/* make a copy of the text */
g_free (priv->clipboard_text);
priv->clipboard_text = g_strdup (text);
/* tell X we own the clipboard selection */
dpy = clutter_x11_get_default_display ();
clutter_x11_trap_x_errors ();
XSetSelectionOwner (dpy, __atom_clip, priv->clipboard_window, CurrentTime);
XSync (dpy, FALSE);
clutter_x11_untrap_x_errors ();
}

94
src/nbtk/nbtk-clipboard.h Normal file
View File

@ -0,0 +1,94 @@
/*
* nbtk-clipboard.h: clipboard object
*
* Copyright 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* Written by: Thomas Wood <thomas.wood@intel.com>
*
*/
#ifndef _NBTK_CLIPBOARD_H
#define _NBTK_CLIPBOARD_H
#include <glib-object.h>
G_BEGIN_DECLS
#define NBTK_TYPE_CLIPBOARD nbtk_clipboard_get_type()
#define NBTK_CLIPBOARD(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
NBTK_TYPE_CLIPBOARD, NbtkClipboard))
#define NBTK_CLIPBOARD_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), \
NBTK_TYPE_CLIPBOARD, NbtkClipboardClass))
#define NBTK_IS_CLIPBOARD(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
NBTK_TYPE_CLIPBOARD))
#define NBTK_IS_CLIPBOARD_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
NBTK_TYPE_CLIPBOARD))
#define NBTK_CLIPBOARD_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
NBTK_TYPE_CLIPBOARD, NbtkClipboardClass))
typedef struct _NbtkClipboard NbtkClipboard;
typedef struct _NbtkClipboardClass NbtkClipboardClass;
typedef struct _NbtkClipboardPrivate NbtkClipboardPrivate;
/**
* NbtkClipboard:
*
* The contents of this structure is private and should only be accessed using
* the provided API.
*/
struct _NbtkClipboard
{
/*< private >*/
GObject parent;
NbtkClipboardPrivate *priv;
};
struct _NbtkClipboardClass
{
GObjectClass parent_class;
};
/**
* NbtkClipboardCallbackFunc:
* @clipboard: A #NbtkClipboard
* @text: text from the clipboard
* @user_data: user data
*
* Callback function called when text is retrieved from the clipboard.
*/
typedef void (*NbtkClipboardCallbackFunc) (NbtkClipboard *clipboard,
const gchar *text,
gpointer user_data);
GType nbtk_clipboard_get_type (void);
NbtkClipboard* nbtk_clipboard_get_default (void);
void nbtk_clipboard_get_text (NbtkClipboard *clipboard, NbtkClipboardCallbackFunc callback, gpointer user_data);
void nbtk_clipboard_set_text (NbtkClipboard *clipboard, const gchar *text);
G_END_DECLS
#endif /* _NBTK_CLIPBOARD_H */

897
src/nbtk/nbtk-entry.c Normal file
View File

@ -0,0 +1,897 @@
/*
* nbtk-entry.c: Plain entry actor
*
* Copyright 2008, 2009 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* Written by: Thomas Wood <thomas.wood@intel.com>
*
*/
/**
* SECTION:nbtk-entry
* @short_description: Widget for displaying text
*
* #NbtkEntry is a simple widget for displaying text. It derives from
* #NbtkWidget to add extra style and placement functionality over
* #ClutterText. The internal #ClutterText is publicly accessibly to allow
* applications to set further properties.
*
* #NbtkEntry supports the following pseudo style states:
* <itemizedlist>
* <listitem>
* <para>focus: the widget has focus</para>
* </listitem>
* <listitem>
* <para>indeterminate: the widget is showing the hint text</para>
* </listitem>
* </itemizedlist>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <clutter/clutter.h>
#include <clutter-imcontext/clutter-imtext.h>
#include "nbtk-entry.h"
#include "nbtk-widget.h"
#include "nbtk-texture-cache.h"
#include "nbtk-marshal.h"
#include "nbtk-clipboard.h"
#define HAS_FOCUS(actor) (clutter_actor_get_stage (actor) && clutter_stage_get_key_focus ((ClutterStage *) clutter_actor_get_stage (actor)) == actor)
/* properties */
enum
{
PROP_0,
PROP_CLUTTER_TEXT,
PROP_HINT_TEXT,
PROP_TEXT,
};
/* signals */
enum
{
PRIMARY_ICON_CLICKED,
SECONDARY_ICON_CLICKED,
LAST_SIGNAL
};
#define NBTK_ENTRY_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NBTK_TYPE_ENTRY, NbtkEntryPrivate))
#define NBTK_ENTRY_PRIV(x) ((NbtkEntry *) x)->priv
struct _NbtkEntryPrivate
{
ClutterActor *entry;
gchar *hint;
ClutterActor *primary_icon;
ClutterActor *secondary_icon;
gfloat spacing;
};
static guint entry_signals[LAST_SIGNAL] = { 0, };
G_DEFINE_TYPE (NbtkEntry, nbtk_entry, NBTK_TYPE_WIDGET);
static void
nbtk_entry_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
NbtkEntry *entry = NBTK_ENTRY (gobject);
switch (prop_id)
{
case PROP_HINT_TEXT:
nbtk_entry_set_hint_text (entry, g_value_get_string (value));
break;
case PROP_TEXT:
nbtk_entry_set_text (entry, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
nbtk_entry_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (gobject);
switch (prop_id)
{
case PROP_CLUTTER_TEXT:
g_value_set_object (value, priv->entry);
break;
case PROP_HINT_TEXT:
g_value_set_string (value, priv->hint);
break;
case PROP_TEXT:
g_value_set_string (value, clutter_text_get_text (CLUTTER_TEXT (priv->entry)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
nbtk_entry_dispose (GObject *object)
{
NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (object);
if (priv->entry)
{
clutter_actor_unparent (priv->entry);
priv->entry = NULL;
}
}
static void
nbtk_entry_finalize (GObject *object)
{
NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (object);
g_free (priv->hint);
priv->hint = NULL;
}
static void
nbtk_entry_style_changed (NbtkWidget *self)
{
NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (self);
ShellThemeNode *theme_node;
ClutterColor color;
const PangoFontDescription *font;
gchar *font_string;
theme_node = nbtk_widget_get_theme_node (self);
shell_theme_node_get_foreground_color (theme_node, &color);
clutter_text_set_color (CLUTTER_TEXT (priv->entry), &color);
if (shell_theme_node_get_color (theme_node, "caret-color", FALSE, &color))
clutter_text_set_cursor_color (CLUTTER_TEXT (priv->entry), &color);
if (shell_theme_node_get_color (theme_node, "selection-background-color", FALSE, &color))
clutter_text_set_selection_color (CLUTTER_TEXT (priv->entry), &color);
font = shell_theme_node_get_font (theme_node);
font_string = pango_font_description_to_string (font);
clutter_text_set_font_name (CLUTTER_TEXT (priv->entry), font_string);
g_free (font_string);
NBTK_WIDGET_CLASS (nbtk_entry_parent_class)->style_changed (self);
}
static void
nbtk_entry_get_preferred_width (ClutterActor *actor,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (actor);
ShellThemeNode *theme_node = nbtk_widget_get_theme_node (NBTK_WIDGET (actor));
gfloat icon_w;
shell_theme_node_adjust_for_height (theme_node, &for_height);
clutter_actor_get_preferred_width (priv->entry, for_height,
min_width_p,
natural_width_p);
if (priv->primary_icon)
{
clutter_actor_get_preferred_width (priv->primary_icon, -1, NULL, &icon_w);
if (min_width_p)
*min_width_p += icon_w + priv->spacing;
if (natural_width_p)
*natural_width_p += icon_w + priv->spacing;
}
if (priv->secondary_icon)
{
clutter_actor_get_preferred_width (priv->secondary_icon,
-1, NULL, &icon_w);
if (min_width_p)
*min_width_p += icon_w + priv->spacing;
if (natural_width_p)
*natural_width_p += icon_w + priv->spacing;
}
shell_theme_node_adjust_preferred_width (theme_node, min_width_p, natural_width_p);
}
static void
nbtk_entry_get_preferred_height (ClutterActor *actor,
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (actor);
ShellThemeNode *theme_node = nbtk_widget_get_theme_node (NBTK_WIDGET (actor));
gfloat icon_h;
shell_theme_node_adjust_for_width (theme_node, &for_width);
clutter_actor_get_preferred_height (priv->entry, for_width,
min_height_p,
natural_height_p);
if (priv->primary_icon)
{
clutter_actor_get_preferred_height (priv->primary_icon,
-1, NULL, &icon_h);
if (min_height_p && icon_h > *min_height_p)
*min_height_p = icon_h;
if (natural_height_p && icon_h > *natural_height_p)
*natural_height_p = icon_h;
}
if (priv->secondary_icon)
{
clutter_actor_get_preferred_height (priv->secondary_icon,
-1, NULL, &icon_h);
if (min_height_p && icon_h > *min_height_p)
*min_height_p = icon_h;
if (natural_height_p && icon_h > *natural_height_p)
*natural_height_p = icon_h;
}
shell_theme_node_adjust_preferred_height (theme_node, min_height_p, natural_height_p);
}
static void
nbtk_entry_allocate (ClutterActor *actor,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (actor);
ShellThemeNode *theme_node = nbtk_widget_get_theme_node (NBTK_WIDGET (actor));
ClutterActorClass *parent_class;
ClutterActorBox content_box, child_box, icon_box;
gfloat icon_w, icon_h;
gfloat entry_h, min_h, pref_h, avail_h;
parent_class = CLUTTER_ACTOR_CLASS (nbtk_entry_parent_class);
parent_class->allocate (actor, box, flags);
shell_theme_node_get_content_box (theme_node, box, &content_box);
avail_h = content_box.y2 - content_box.y1;
child_box.x1 = content_box.x1;
child_box.x2 = content_box.x2;
if (priv->primary_icon)
{
clutter_actor_get_preferred_width (priv->primary_icon,
-1, NULL, &icon_w);
clutter_actor_get_preferred_height (priv->primary_icon,
-1, NULL, &icon_h);
icon_box.x1 = content_box.x1;
icon_box.x2 = icon_box.x1 + icon_w;
icon_box.y1 = (int) (content_box.y1 + avail_h / 2 - icon_h / 2);
icon_box.y2 = icon_box.y1 + icon_h;
clutter_actor_allocate (priv->primary_icon,
&icon_box,
flags);
/* reduce the size for the entry */
child_box.x1 += icon_w + priv->spacing;
}
if (priv->secondary_icon)
{
clutter_actor_get_preferred_width (priv->secondary_icon,
-1, NULL, &icon_w);
clutter_actor_get_preferred_height (priv->secondary_icon,
-1, NULL, &icon_h);
icon_box.x2 = content_box.x2;
icon_box.x1 = icon_box.x2 - icon_w;
icon_box.y1 = (int) (content_box.y1 + avail_h / 2 - icon_h / 2);
icon_box.y2 = icon_box.y1 + icon_h;
clutter_actor_allocate (priv->secondary_icon,
&icon_box,
flags);
/* reduce the size for the entry */
child_box.x2 -= icon_w - priv->spacing;
}
clutter_actor_get_preferred_height (priv->entry, child_box.x2 - child_box.x1,
&min_h, &pref_h);
entry_h = CLAMP (pref_h, min_h, avail_h);
child_box.y1 = (int) (content_box.y1 + avail_h / 2 - entry_h / 2);
child_box.y2 = child_box.y1 + entry_h;
clutter_actor_allocate (priv->entry, &child_box, flags);
}
static void
clutter_text_focus_in_cb (ClutterText *text,
ClutterActor *actor)
{
NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (actor);
/* remove the hint if visible */
if (priv->hint
&& !strcmp (clutter_text_get_text (text), priv->hint))
{
clutter_text_set_text (text, "");
}
nbtk_widget_set_style_pseudo_class (NBTK_WIDGET (actor), "focus");
clutter_text_set_cursor_visible (text, TRUE);
}
static void
clutter_text_focus_out_cb (ClutterText *text,
ClutterActor *actor)
{
NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (actor);
/* add a hint if the entry is empty */
if (priv->hint && !strcmp (clutter_text_get_text (text), ""))
{
clutter_text_set_text (text, priv->hint);
nbtk_widget_set_style_pseudo_class (NBTK_WIDGET (actor), "indeterminate");
}
else
{
nbtk_widget_set_style_pseudo_class (NBTK_WIDGET (actor), NULL);
}
clutter_text_set_cursor_visible (text, FALSE);
}
static void
nbtk_entry_paint (ClutterActor *actor)
{
NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (actor);
ClutterActorClass *parent_class;
parent_class = CLUTTER_ACTOR_CLASS (nbtk_entry_parent_class);
parent_class->paint (actor);
clutter_actor_paint (priv->entry);
if (priv->primary_icon)
clutter_actor_paint (priv->primary_icon);
if (priv->secondary_icon)
clutter_actor_paint (priv->secondary_icon);
}
static void
nbtk_entry_pick (ClutterActor *actor,
const ClutterColor *c)
{
NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (actor);
CLUTTER_ACTOR_CLASS (nbtk_entry_parent_class)->pick (actor, c);
clutter_actor_paint (priv->entry);
if (priv->primary_icon)
clutter_actor_paint (priv->primary_icon);
if (priv->secondary_icon)
clutter_actor_paint (priv->secondary_icon);
}
static void
nbtk_entry_map (ClutterActor *actor)
{
NbtkEntryPrivate *priv = NBTK_ENTRY (actor)->priv;
CLUTTER_ACTOR_CLASS (nbtk_entry_parent_class)->map (actor);
clutter_actor_map (priv->entry);
if (priv->primary_icon)
clutter_actor_map (priv->primary_icon);
if (priv->secondary_icon)
clutter_actor_map (priv->secondary_icon);
}
static void
nbtk_entry_unmap (ClutterActor *actor)
{
NbtkEntryPrivate *priv = NBTK_ENTRY (actor)->priv;
CLUTTER_ACTOR_CLASS (nbtk_entry_parent_class)->unmap (actor);
clutter_actor_unmap (priv->entry);
if (priv->primary_icon)
clutter_actor_unmap (priv->primary_icon);
if (priv->secondary_icon)
clutter_actor_unmap (priv->secondary_icon);
}
static void
nbtk_entry_clipboard_callback (NbtkClipboard *clipboard,
const gchar *text,
gpointer data)
{
ClutterText *ctext = (ClutterText*) ((NbtkEntry *) data)->priv->entry;
gint cursor_pos;
if (!text)
return;
/* delete the current selection before pasting */
clutter_text_delete_selection (ctext);
/* "paste" the clipboard text into the entry */
cursor_pos = clutter_text_get_cursor_position (ctext);
clutter_text_insert_text (ctext, text, cursor_pos);
}
static gboolean
nbtk_entry_key_press_event (ClutterActor *actor,
ClutterKeyEvent *event)
{
NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (actor);
/* This is expected to handle events that were emitted for the inner
ClutterText. They only reach this function if the ClutterText
didn't handle them */
/* paste */
if ((event->modifier_state & CLUTTER_CONTROL_MASK)
&& event->keyval == CLUTTER_v)
{
NbtkClipboard *clipboard;
clipboard = nbtk_clipboard_get_default ();
nbtk_clipboard_get_text (clipboard, nbtk_entry_clipboard_callback, actor);
return TRUE;
}
/* copy */
if ((event->modifier_state & CLUTTER_CONTROL_MASK)
&& event->keyval == CLUTTER_c)
{
NbtkClipboard *clipboard;
gchar *text;
clipboard = nbtk_clipboard_get_default ();
text = clutter_text_get_selection ((ClutterText*) priv->entry);
if (text && strlen (text))
nbtk_clipboard_set_text (clipboard, text);
return TRUE;
}
/* cut */
if ((event->modifier_state & CLUTTER_CONTROL_MASK)
&& event->keyval == CLUTTER_x)
{
NbtkClipboard *clipboard;
gchar *text;
clipboard = nbtk_clipboard_get_default ();
text = clutter_text_get_selection ((ClutterText*) priv->entry);
if (text && strlen (text))
{
nbtk_clipboard_set_text (clipboard, text);
/* now delete the text */
clutter_text_delete_selection ((ClutterText *) priv->entry);
}
return TRUE;
}
return FALSE;
}
static void
nbtk_entry_key_focus_in (ClutterActor *actor)
{
NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (actor);
/* We never want key focus. The ClutterText should be given first
pass for all key events */
clutter_actor_grab_key_focus (priv->entry);
}
static void
nbtk_entry_class_init (NbtkEntryClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
NbtkWidgetClass *widget_class = NBTK_WIDGET_CLASS (klass);
GParamSpec *pspec;
g_type_class_add_private (klass, sizeof (NbtkEntryPrivate));
gobject_class->set_property = nbtk_entry_set_property;
gobject_class->get_property = nbtk_entry_get_property;
gobject_class->finalize = nbtk_entry_finalize;
gobject_class->dispose = nbtk_entry_dispose;
actor_class->get_preferred_width = nbtk_entry_get_preferred_width;
actor_class->get_preferred_height = nbtk_entry_get_preferred_height;
actor_class->allocate = nbtk_entry_allocate;
actor_class->paint = nbtk_entry_paint;
actor_class->pick = nbtk_entry_pick;
actor_class->map = nbtk_entry_map;
actor_class->unmap = nbtk_entry_unmap;
actor_class->key_press_event = nbtk_entry_key_press_event;
actor_class->key_focus_in = nbtk_entry_key_focus_in;
widget_class->style_changed = nbtk_entry_style_changed;
pspec = g_param_spec_object ("clutter-text",
"Clutter Text",
"Internal ClutterText actor",
CLUTTER_TYPE_TEXT,
G_PARAM_READABLE);
g_object_class_install_property (gobject_class, PROP_CLUTTER_TEXT, pspec);
pspec = g_param_spec_string ("hint-text",
"Hint Text",
"Text to display when the entry is not focused "
"and the text property is empty",
NULL, G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_HINT_TEXT, pspec);
pspec = g_param_spec_string ("text",
"Text",
"Text of the entry",
NULL, G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_TEXT, pspec);
/* signals */
/**
* NbtkEntry::primary-icon-clicked:
*
* Emitted when the primary icon is clicked
*/
entry_signals[PRIMARY_ICON_CLICKED] =
g_signal_new ("primary-icon-clicked",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NbtkEntryClass, primary_icon_clicked),
NULL, NULL,
_nbtk_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/**
* NbtkEntry::secondary-icon-clicked:
*
* Emitted when the secondary icon is clicked
*/
entry_signals[SECONDARY_ICON_CLICKED] =
g_signal_new ("secondary-icon-clicked",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NbtkEntryClass, secondary_icon_clicked),
NULL, NULL,
_nbtk_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static void
nbtk_entry_init (NbtkEntry *entry)
{
NbtkEntryPrivate *priv;
priv = entry->priv = NBTK_ENTRY_GET_PRIVATE (entry);
priv->entry = g_object_new (CLUTTER_TYPE_IMTEXT,
"line-alignment", PANGO_ALIGN_LEFT,
"editable", TRUE,
"reactive", TRUE,
"single-line-mode", TRUE,
NULL);
g_signal_connect (priv->entry, "key-focus-in",
G_CALLBACK (clutter_text_focus_in_cb), entry);
g_signal_connect (priv->entry, "key-focus-out",
G_CALLBACK (clutter_text_focus_out_cb), entry);
priv->spacing = 6.0f;
clutter_actor_set_parent (priv->entry, CLUTTER_ACTOR (entry));
clutter_actor_set_reactive ((ClutterActor *) entry, TRUE);
/* set cursor hidden until we receive focus */
clutter_text_set_cursor_visible ((ClutterText *) priv->entry, FALSE);
}
/**
* nbtk_entry_new:
* @text: text to set the entry to
*
* Create a new #NbtkEntry with the specified entry
*
* Returns: a new #NbtkEntry
*/
NbtkWidget *
nbtk_entry_new (const gchar *text)
{
NbtkWidget *entry;
/* add the entry to the stage, but don't allow it to be visible */
entry = g_object_new (NBTK_TYPE_ENTRY,
"text", text,
NULL);
return entry;
}
/**
* nbtk_entry_get_text:
* @entry: a #NbtkEntry
*
* Get the text displayed on the entry
*
* Returns: the text for the entry. This must not be freed by the application
*/
G_CONST_RETURN gchar *
nbtk_entry_get_text (NbtkEntry *entry)
{
g_return_val_if_fail (NBTK_IS_ENTRY (entry), NULL);
return clutter_text_get_text (CLUTTER_TEXT (entry->priv->entry));
}
/**
* nbtk_entry_set_text:
* @entry: a #NbtkEntry
* @text: text to set the entry to
*
* Sets the text displayed on the entry
*/
void
nbtk_entry_set_text (NbtkEntry *entry,
const gchar *text)
{
NbtkEntryPrivate *priv;
g_return_if_fail (NBTK_IS_ENTRY (entry));
priv = entry->priv;
/* set a hint if we are blanking the entry */
if (priv->hint
&& text && !strcmp ("", text)
&& !HAS_FOCUS (priv->entry))
{
text = priv->hint;
nbtk_widget_set_style_pseudo_class (NBTK_WIDGET (entry), "indeterminate");
}
else
{
if (HAS_FOCUS (priv->entry))
nbtk_widget_set_style_pseudo_class (NBTK_WIDGET (entry), "focus");
else
nbtk_widget_set_style_pseudo_class (NBTK_WIDGET (entry), NULL);
}
clutter_text_set_text (CLUTTER_TEXT (priv->entry), text);
g_object_notify (G_OBJECT (entry), "text");
}
/**
* nbtk_entry_get_clutter_text:
* @entry: a #NbtkEntry
*
* Retrieve the internal #ClutterText so that extra parameters can be set
*
* Returns: (transfer none): the #ClutterText used by #NbtkEntry. The entry is
* owned by the #NbtkEntry and should not be unref'ed by the application.
*/
ClutterActor*
nbtk_entry_get_clutter_text (NbtkEntry *entry)
{
g_return_val_if_fail (NBTK_ENTRY (entry), NULL);
return entry->priv->entry;
}
/**
* nbtk_entry_set_hint_text:
* @entry: a #NbtkEntry
* @text: text to set as the entry hint
*
* Sets the text to display when the entry is empty and unfocused. When the
* entry is displaying the hint, it has a pseudo class of "indeterminate".
* A value of NULL unsets the hint.
*/
void
nbtk_entry_set_hint_text (NbtkEntry *entry,
const gchar *text)
{
NbtkEntryPrivate *priv;
g_return_if_fail (NBTK_IS_ENTRY (entry));
priv = entry->priv;
g_free (priv->hint);
priv->hint = g_strdup (text);
if (!strcmp (clutter_text_get_text (CLUTTER_TEXT (priv->entry)), ""))
{
clutter_text_set_text (CLUTTER_TEXT (priv->entry), priv->hint);
nbtk_widget_set_style_pseudo_class (NBTK_WIDGET (entry), "indeterminate");
}
}
/**
* nbtk_entry_get_hint_text:
* @entry: a #NbtkEntry
*
* Gets the text that is displayed when the entry is empty and unfocused
*
* Returns: the current value of the hint property. This string is owned by the
* #NbtkEntry and should not be freed or modified.
*/
G_CONST_RETURN
gchar *
nbtk_entry_get_hint_text (NbtkEntry *entry)
{
g_return_val_if_fail (NBTK_IS_ENTRY (entry), NULL);
return entry->priv->hint;
}
static gboolean
_nbtk_entry_icon_press_cb (ClutterActor *actor,
ClutterButtonEvent *event,
NbtkEntry *entry)
{
NbtkEntryPrivate *priv = entry->priv;
if (actor == priv->primary_icon)
g_signal_emit (entry, entry_signals[PRIMARY_ICON_CLICKED], 0);
else
g_signal_emit (entry, entry_signals[SECONDARY_ICON_CLICKED], 0);
return FALSE;
}
static void
_nbtk_entry_set_icon_from_file (NbtkEntry *entry,
ClutterActor **icon,
const gchar *filename)
{
if (*icon)
{
g_signal_handlers_disconnect_by_func (*icon,
_nbtk_entry_icon_press_cb,
entry);
clutter_actor_unparent (*icon);
*icon = NULL;
}
if (filename)
{
NbtkTextureCache *cache;
cache = nbtk_texture_cache_get_default ();
*icon = (ClutterActor*) nbtk_texture_cache_get_texture (cache, filename, FALSE);
clutter_actor_set_reactive (*icon, TRUE);
clutter_actor_set_parent (*icon, CLUTTER_ACTOR (entry));
g_signal_connect (*icon, "button-release-event",
G_CALLBACK (_nbtk_entry_icon_press_cb), entry);
}
clutter_actor_queue_relayout (CLUTTER_ACTOR (entry));
}
/**
* nbtk_entry_set_primary_icon_from_file:
* @entry: a #NbtkEntry
* @filename: filename of an icon
*
* Set the primary icon of the entry to the given filename
*/
void
nbtk_entry_set_primary_icon_from_file (NbtkEntry *entry,
const gchar *filename)
{
NbtkEntryPrivate *priv;
g_return_if_fail (NBTK_IS_ENTRY (entry));
priv = entry->priv;
_nbtk_entry_set_icon_from_file (entry, &priv->primary_icon, filename);
}
/**
* nbtk_entry_set_secondary_icon_from_file:
* @entry: a #NbtkEntry
* @filename: filename of an icon
*
* Set the primary icon of the entry to the given filename
*/
void
nbtk_entry_set_secondary_icon_from_file (NbtkEntry *entry,
const gchar *filename)
{
NbtkEntryPrivate *priv;
g_return_if_fail (NBTK_IS_ENTRY (entry));
priv = entry->priv;
_nbtk_entry_set_icon_from_file (entry, &priv->secondary_icon, filename);
}

88
src/nbtk/nbtk-entry.h Normal file
View File

@ -0,0 +1,88 @@
/*
* nbtk-entry.h: Plain entry actor
*
* Copyright 2008, 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
* Written by: Thomas Wood <thomas@linux.intel.com>
*
*/
#if !defined(NBTK_H_INSIDE) && !defined(NBTK_COMPILATION)
#error "Only <nbtk/nbtk.h> can be included directly.h"
#endif
#ifndef __NBTK_ENTRY_H__
#define __NBTK_ENTRY_H__
G_BEGIN_DECLS
#include <nbtk/nbtk-widget.h>
#define NBTK_TYPE_ENTRY (nbtk_entry_get_type ())
#define NBTK_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NBTK_TYPE_ENTRY, NbtkEntry))
#define NBTK_IS_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NBTK_TYPE_ENTRY))
#define NBTK_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NBTK_TYPE_ENTRY, NbtkEntryClass))
#define NBTK_IS_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NBTK_TYPE_ENTRY))
#define NBTK_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NBTK_TYPE_ENTRY, NbtkEntryClass))
typedef struct _NbtkEntry NbtkEntry;
typedef struct _NbtkEntryPrivate NbtkEntryPrivate;
typedef struct _NbtkEntryClass NbtkEntryClass;
/**
* NbtkEntry:
*
* The contents of this structure is private and should only be accessed using
* the provided API.
*/
struct _NbtkEntry
{
/*< private >*/
NbtkWidget parent_instance;
NbtkEntryPrivate *priv;
};
struct _NbtkEntryClass
{
NbtkWidgetClass parent_class;
/* signals */
void (*primary_icon_clicked) (NbtkEntry *entry);
void (*secondary_icon_clicked) (NbtkEntry *entry);
};
GType nbtk_entry_get_type (void) G_GNUC_CONST;
NbtkWidget * nbtk_entry_new (const gchar *text);
G_CONST_RETURN gchar *nbtk_entry_get_text (NbtkEntry *entry);
void nbtk_entry_set_text (NbtkEntry *entry,
const gchar *text);
ClutterActor* nbtk_entry_get_clutter_text (NbtkEntry *entry);
void nbtk_entry_set_hint_text (NbtkEntry *entry,
const gchar *text);
G_CONST_RETURN gchar *nbtk_entry_get_hint_text (NbtkEntry *entry);
void nbtk_entry_set_primary_icon_from_file (NbtkEntry *entry,
const gchar *filename);
void nbtk_entry_set_secondary_icon_from_file (NbtkEntry *entry,
const gchar *filename);
G_END_DECLS
#endif /* __NBTK_ENTRY_H__ */

View File

@ -0,0 +1,30 @@
/*** BEGIN file-header ***/
#include "nbtk-enum-types.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 ***/

View File

@ -0,0 +1,29 @@
/*** BEGIN file-header ***/
#if !defined(NBTK_H_INSIDE) && !defined(NBTK_COMPILATION)
#error "Only <nbtk/nbtk.h> can be included directly.h"
#endif
#ifndef __NBTK_ENUM_TYPES_H__
#define __NBTK_ENUM_TYPES_H__
#include <glib-object.h>
G_BEGIN_DECLS
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@filename@" */
/*** END file-production ***/
/*** BEGIN file-tail ***/
G_END_DECLS
#endif /* !__NBTK_ENUM_TYPES_H__ */
/*** END file-tail ***/
/*** BEGIN value-header ***/
GType @enum_name@_get_type (void) G_GNUC_CONST;
#define NBTK_TYPE_@ENUMSHORT@ (@enum_name@_get_type())
/*** END value-header ***/

341
src/nbtk/nbtk-label.c Normal file
View File

@ -0,0 +1,341 @@
/*
* nbtk-label.c: Plain label actor
*
* Copyright 2008,2009 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* Written by: Thomas Wood <thomas@linux.intel.com>
*
*/
/**
* SECTION:nbtk-label
* @short_description: Widget for displaying text
*
* #NbtkLabel is a simple widget for displaying text. It derives from
* #NbtkWidget to add extra style and placement functionality over
* #ClutterText. The internal #ClutterText is publicly accessibly to allow
* applications to set further properties.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <clutter/clutter.h>
#include "nbtk-label.h"
#include "nbtk-widget.h"
enum
{
PROP_0,
PROP_CLUTTER_TEXT,
PROP_TEXT
};
#define NBTK_LABEL_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NBTK_TYPE_LABEL, NbtkLabelPrivate))
struct _NbtkLabelPrivate
{
ClutterActor *label;
};
G_DEFINE_TYPE (NbtkLabel, nbtk_label, NBTK_TYPE_WIDGET);
static void
nbtk_label_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
NbtkLabel *label = NBTK_LABEL (gobject);
switch (prop_id)
{
case PROP_TEXT:
nbtk_label_set_text (label, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
nbtk_label_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
NbtkLabelPrivate *priv = NBTK_LABEL (gobject)->priv;
switch (prop_id)
{
case PROP_CLUTTER_TEXT:
g_value_set_object (value, priv->label);
break;
case PROP_TEXT:
g_value_set_string (value, clutter_text_get_text (CLUTTER_TEXT (priv->label)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
nbtk_label_style_changed (NbtkWidget *self)
{
NbtkLabelPrivate *priv;
ShellThemeNode *theme_node;
ClutterColor color;
const PangoFontDescription *font;
gchar *font_string;
priv = NBTK_LABEL (self)->priv;
theme_node = nbtk_widget_get_theme_node (self);
shell_theme_node_get_foreground_color (theme_node, &color);
clutter_text_set_color (CLUTTER_TEXT (priv->label), &color);
font = shell_theme_node_get_font (theme_node);
font_string = pango_font_description_to_string (font);
clutter_text_set_font_name (CLUTTER_TEXT (priv->label), font_string);
g_free (font_string);
NBTK_WIDGET_CLASS (nbtk_label_parent_class)->style_changed (self);
}
static void
nbtk_label_get_preferred_width (ClutterActor *actor,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
NbtkLabelPrivate *priv = NBTK_LABEL (actor)->priv;
ShellThemeNode *theme_node = nbtk_widget_get_theme_node (NBTK_WIDGET (actor));
shell_theme_node_adjust_for_height (theme_node, &for_height);
clutter_actor_get_preferred_width (priv->label, for_height,
min_width_p,
natural_width_p);
shell_theme_node_adjust_preferred_width (theme_node, min_width_p, natural_width_p);
}
static void
nbtk_label_get_preferred_height (ClutterActor *actor,
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
NbtkLabelPrivate *priv = NBTK_LABEL (actor)->priv;
ShellThemeNode *theme_node = nbtk_widget_get_theme_node (NBTK_WIDGET (actor));
shell_theme_node_adjust_for_width (theme_node, &for_width);
clutter_actor_get_preferred_height (priv->label, for_width,
min_height_p,
natural_height_p);
shell_theme_node_adjust_preferred_height (theme_node, min_height_p, natural_height_p);
}
static void
nbtk_label_allocate (ClutterActor *actor,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
NbtkLabelPrivate *priv = NBTK_LABEL (actor)->priv;
ShellThemeNode *theme_node = nbtk_widget_get_theme_node (NBTK_WIDGET (actor));
ClutterActorClass *parent_class;
ClutterActorBox content_box;
shell_theme_node_get_content_box (theme_node, box, &content_box);
parent_class = CLUTTER_ACTOR_CLASS (nbtk_label_parent_class);
parent_class->allocate (actor, box, flags);
clutter_actor_allocate (priv->label, &content_box, flags);
}
static void
nbtk_label_paint (ClutterActor *actor)
{
NbtkLabelPrivate *priv = NBTK_LABEL (actor)->priv;
ClutterActorClass *parent_class;
parent_class = CLUTTER_ACTOR_CLASS (nbtk_label_parent_class);
parent_class->paint (actor);
clutter_actor_paint (priv->label);
}
static void
nbtk_label_map (ClutterActor *actor)
{
NbtkLabelPrivate *priv = NBTK_LABEL (actor)->priv;
CLUTTER_ACTOR_CLASS (nbtk_label_parent_class)->map (actor);
clutter_actor_map (priv->label);
}
static void
nbtk_label_unmap (ClutterActor *actor)
{
NbtkLabelPrivate *priv = NBTK_LABEL (actor)->priv;
CLUTTER_ACTOR_CLASS (nbtk_label_parent_class)->unmap (actor);
clutter_actor_unmap (priv->label);
}
static void
nbtk_label_class_init (NbtkLabelClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
NbtkWidgetClass *widget_class = NBTK_WIDGET_CLASS (klass);
GParamSpec *pspec;
g_type_class_add_private (klass, sizeof (NbtkLabelPrivate));
gobject_class->set_property = nbtk_label_set_property;
gobject_class->get_property = nbtk_label_get_property;
actor_class->paint = nbtk_label_paint;
actor_class->allocate = nbtk_label_allocate;
actor_class->get_preferred_width = nbtk_label_get_preferred_width;
actor_class->get_preferred_height = nbtk_label_get_preferred_height;
actor_class->map = nbtk_label_map;
actor_class->unmap = nbtk_label_unmap;
widget_class->style_changed = nbtk_label_style_changed;
pspec = g_param_spec_object ("clutter-text",
"Clutter Text",
"Internal ClutterText actor",
CLUTTER_TYPE_TEXT,
G_PARAM_READABLE);
g_object_class_install_property (gobject_class, PROP_CLUTTER_TEXT, pspec);
pspec = g_param_spec_string ("text",
"Text",
"Text of the label",
NULL, G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_TEXT, pspec);
}
static void
nbtk_label_init (NbtkLabel *label)
{
NbtkLabelPrivate *priv;
label->priv = priv = NBTK_LABEL_GET_PRIVATE (label);
label->priv->label = g_object_new (CLUTTER_TYPE_TEXT,
"ellipsize", PANGO_ELLIPSIZE_END,
NULL);
clutter_actor_set_parent (priv->label, CLUTTER_ACTOR (label));
}
/**
* nbtk_label_new:
* @text: text to set the label to
*
* Create a new #NbtkLabel with the specified label
*
* Returns: a new #NbtkLabel
*/
NbtkWidget *
nbtk_label_new (const gchar *text)
{
if (text == NULL || *text == '\0')
return g_object_new (NBTK_TYPE_LABEL, NULL);
else
return g_object_new (NBTK_TYPE_LABEL,
"text", text,
NULL);
}
/**
* nbtk_label_get_text:
* @label: a #NbtkLabel
*
* Get the text displayed on the label
*
* Returns: the text for the label. This must not be freed by the application
*/
G_CONST_RETURN gchar *
nbtk_label_get_text (NbtkLabel *label)
{
g_return_val_if_fail (NBTK_IS_LABEL (label), NULL);
return clutter_text_get_text (CLUTTER_TEXT (label->priv->label));
}
/**
* nbtk_label_set_text:
* @label: a #NbtkLabel
* @text: text to set the label to
*
* Sets the text displayed on the label
*/
void
nbtk_label_set_text (NbtkLabel *label,
const gchar *text)
{
NbtkLabelPrivate *priv;
g_return_if_fail (NBTK_IS_LABEL (label));
g_return_if_fail (text != NULL);
priv = label->priv;
clutter_text_set_text (CLUTTER_TEXT (priv->label), text);
g_object_notify (G_OBJECT (label), "text");
}
/**
* nbtk_label_get_clutter_text:
* @label: a #NbtkLabel
*
* Retrieve the internal #ClutterText so that extra parameters can be set
*
* Returns: (transfer none): ethe #ClutterText used by #NbtkLabel. The label
* is owned by the #NbtkLabel and should not be unref'ed by the application.
*/
ClutterActor*
nbtk_label_get_clutter_text (NbtkLabel *label)
{
g_return_val_if_fail (NBTK_LABEL (label), NULL);
return label->priv->label;
}

75
src/nbtk/nbtk-label.h Normal file
View File

@ -0,0 +1,75 @@
/*
* nbtk-label.h: Plain label actor
*
* Copyright 2008, 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
* Written by: Thomas Wood <thomas@linux.intel.com>
*
*/
#if !defined(NBTK_H_INSIDE) && !defined(NBTK_COMPILATION)
#error "Only <nbtk/nbtk.h> can be included directly.h"
#endif
#ifndef __NBTK_LABEL_H__
#define __NBTK_LABEL_H__
G_BEGIN_DECLS
#include <nbtk/nbtk-widget.h>
#define NBTK_TYPE_LABEL (nbtk_label_get_type ())
#define NBTK_LABEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NBTK_TYPE_LABEL, NbtkLabel))
#define NBTK_IS_LABEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NBTK_TYPE_LABEL))
#define NBTK_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NBTK_TYPE_LABEL, NbtkLabelClass))
#define NBTK_IS_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NBTK_TYPE_LABEL))
#define NBTK_LABEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NBTK_TYPE_LABEL, NbtkLabelClass))
typedef struct _NbtkLabel NbtkLabel;
typedef struct _NbtkLabelPrivate NbtkLabelPrivate;
typedef struct _NbtkLabelClass NbtkLabelClass;
/**
* NbtkLabel:
*
* The contents of this structure is private and should only be accessed using
* the provided API.
*/
struct _NbtkLabel
{
/*< private >*/
NbtkWidget parent_instance;
NbtkLabelPrivate *priv;
};
struct _NbtkLabelClass
{
NbtkWidgetClass parent_class;
};
GType nbtk_label_get_type (void) G_GNUC_CONST;
NbtkWidget * nbtk_label_new (const gchar *text);
G_CONST_RETURN gchar *nbtk_label_get_text (NbtkLabel *label);
void nbtk_label_set_text (NbtkLabel *label,
const gchar *text);
ClutterActor * nbtk_label_get_clutter_text (NbtkLabel *label);
G_END_DECLS
#endif /* __NBTK_LABEL_H__ */

View File

@ -0,0 +1,12 @@
VOID:OBJECT
VOID:VOID
VOID:PARAM
VOID:POINTER
VOID:UINT
VOID:UINT,UINT
VOID:OBJECT,OBJECT
VOID:STRING,OBJECT
VOID:OBJECT,OBJECT,INT,INT
VOID:OBJECT,FLOAT,FLOAT,INT,ENUM
VOID:FLOAT,FLOAT,INT,ENUM
VOID:FLOAT,FLOAT

111
src/nbtk/nbtk-private.c Normal file
View File

@ -0,0 +1,111 @@
#include "nbtk-private.h"
/* Utility function to modify a child allocation box with respect to the
* x/y-fill child properties. Expects childbox to contain the available
* allocation space.
*/
void
_nbtk_allocate_fill (ClutterActor *child,
ClutterActorBox *childbox,
NbtkAlign x_alignment,
NbtkAlign y_alignment,
gboolean x_fill,
gboolean y_fill)
{
gfloat natural_width, natural_height;
gfloat min_width, min_height;
gfloat child_width, child_height;
gfloat available_width, available_height;
ClutterRequestMode request;
ClutterActorBox allocation = { 0, };
gdouble x_align, y_align;
if (x_alignment == NBTK_ALIGN_START)
x_align = 0.0;
else if (x_alignment == NBTK_ALIGN_MIDDLE)
x_align = 0.5;
else
x_align = 1.0;
if (y_alignment == NBTK_ALIGN_START)
y_align = 0.0;
else if (y_alignment == NBTK_ALIGN_MIDDLE)
y_align = 0.5;
else
y_align = 1.0;
available_width = childbox->x2 - childbox->x1;
available_height = childbox->y2 - childbox->y1;
if (available_width < 0)
available_width = 0;
if (available_height < 0)
available_height = 0;
if (x_fill)
{
allocation.x1 = childbox->x1;
allocation.x2 = (int) (allocation.x1 + available_width);
}
if (y_fill)
{
allocation.y1 = childbox->y1;
allocation.y2 = (int) (allocation.y1 + available_height);
}
/* if we are filling horizontally and vertically then we're done */
if (x_fill && y_fill)
{
*childbox = allocation;
return;
}
request = CLUTTER_REQUEST_HEIGHT_FOR_WIDTH;
g_object_get (G_OBJECT (child), "request-mode", &request, NULL);
if (request == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
{
clutter_actor_get_preferred_width (child, available_height,
&min_width,
&natural_width);
child_width = CLAMP (natural_width, min_width, available_width);
clutter_actor_get_preferred_height (child, child_width,
&min_height,
&natural_height);
child_height = CLAMP (natural_height, min_height, available_height);
}
else
{
clutter_actor_get_preferred_height (child, available_width,
&min_height,
&natural_height);
child_height = CLAMP (natural_height, min_height, available_height);
clutter_actor_get_preferred_width (child, child_height,
&min_width,
&natural_width);
child_width = CLAMP (natural_width, min_width, available_width);
}
if (!x_fill)
{
allocation.x1 = childbox->x1 + (int) ((available_width - child_width) * x_align);
allocation.x2 = allocation.x1 + (int) child_width;
}
if (!y_fill)
{
allocation.y1 = childbox->y1 + (int) ((available_height - child_height) * y_align);
allocation.y2 = allocation.y1 + (int) child_height;
}
*childbox = allocation;
}

49
src/nbtk/nbtk-private.h Normal file
View File

@ -0,0 +1,49 @@
/*
* nbtk-private.h: Private declarations
*
* Copyright 2007 OpenedHand
* Copyright 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
*/
#ifndef __NBTK_PRIVATE_H__
#define __NBTK_PRIVATE_H__
#include <glib.h>
#include "nbtk-widget.h"
#include "nbtk-bin.h"
G_BEGIN_DECLS
#define I_(str) (g_intern_static_string ((str)))
#define NBTK_PARAM_READABLE \
(G_PARAM_READABLE | \
G_PARAM_STATIC_NICK | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB)
#define NBTK_PARAM_READWRITE \
(G_PARAM_READABLE | G_PARAM_WRITABLE | \
G_PARAM_STATIC_NICK | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB)
G_END_DECLS
ClutterActor *_nbtk_widget_get_dnd_clone (NbtkWidget *widget);
void _nbtk_bin_get_align_factors (NbtkBin *bin, gdouble *x_align, gdouble *y_align);
void _nbtk_allocate_fill (ClutterActor *child, ClutterActorBox *childbox, NbtkAlign x_align, NbtkAlign y_align, gboolean x_fill, gboolean y_fill);
#endif /* __NBTK_PRIVATE_H__ */

1065
src/nbtk/nbtk-scroll-bar.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,81 @@
/*
* nbtk-scroll-bar.h: Scroll bar actor
*
* Copyright 2008 OpenedHand
* Copyright 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
* Written by: Chris Lord <chris@openedhand.com>
* Port to Nbtk by: Robert Staudinger <robsta@openedhand.com>
*
*/
#if !defined(NBTK_H_INSIDE) && !defined(NBTK_COMPILATION)
#error "Only <nbtk/nbtk.h> can be included directly.h"
#endif
#ifndef __NBTK_SCROLL_BAR_H__
#define __NBTK_SCROLL_BAR_H__
#include <nbtk/nbtk-adjustment.h>
#include <nbtk/nbtk-bin.h>
G_BEGIN_DECLS
#define NBTK_TYPE_SCROLL_BAR (nbtk_scroll_bar_get_type())
#define NBTK_SCROLL_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NBTK_TYPE_SCROLL_BAR, NbtkScrollBar))
#define NBTK_IS_SCROLL_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NBTK_TYPE_SCROLL_BAR))
#define NBTK_SCROLL_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NBTK_TYPE_SCROLL_BAR, NbtkScrollBarClass))
#define NBTK_IS_SCROLL_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NBTK_TYPE_SCROLL_BAR))
#define NBTK_SCROLL_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NBTK_TYPE_SCROLL_BAR, NbtkScrollBarClass))
typedef struct _NbtkScrollBar NbtkScrollBar;
typedef struct _NbtkScrollBarPrivate NbtkScrollBarPrivate;
typedef struct _NbtkScrollBarClass NbtkScrollBarClass;
/**
* NbtkScrollBar:
*
* The contents of this structure are private and should only be accessed
* through the public API.
*/
struct _NbtkScrollBar
{
/*< private >*/
NbtkBin parent_instance;
NbtkScrollBarPrivate *priv;
};
struct _NbtkScrollBarClass
{
NbtkBinClass parent_class;
/* signals */
void (*scroll_start) (NbtkScrollBar *bar);
void (*scroll_stop) (NbtkScrollBar *bar);
};
GType nbtk_scroll_bar_get_type (void) G_GNUC_CONST;
NbtkWidget * nbtk_scroll_bar_new (NbtkAdjustment *adjustment);
void nbtk_scroll_bar_set_adjustment (NbtkScrollBar *bar,
NbtkAdjustment *adjustment);
NbtkAdjustment *nbtk_scroll_bar_get_adjustment (NbtkScrollBar *bar);
G_END_DECLS
#endif /* __NBTK_SCROLL_BAR_H__ */

829
src/nbtk/nbtk-scroll-view.c Normal file
View File

@ -0,0 +1,829 @@
/*
* nbtk-scroll-view.h: Container with scroll-bars
*
* Copyright 2008 OpenedHand
* Copyright 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* Written by: Chris Lord <chris@openedhand.com>
* Port to Nbtk by: Robert Staudinger <robsta@openedhand.com>
*
*/
#include "nbtk-scroll-view.h"
#include "nbtk-marshal.h"
#include "nbtk-scroll-bar.h"
#include "nbtk-scrollable.h"
#include <clutter/clutter.h>
static void clutter_container_iface_init (ClutterContainerIface *iface);
static ClutterContainerIface *nbtk_scroll_view_parent_iface = NULL;
G_DEFINE_TYPE_WITH_CODE (NbtkScrollView, nbtk_scroll_view, NBTK_TYPE_BIN,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
clutter_container_iface_init))
#define SCROLL_VIEW_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
NBTK_TYPE_SCROLL_VIEW, \
NbtkScrollViewPrivate))
/* Default width (or height - the narrow dimension) for the scrollbars*/
#define DEFAULT_SCROLLBAR_WIDTH 24
struct _NbtkScrollViewPrivate
{
/* a pointer to the child; this is actually stored
* inside NbtkBin:child, but we keep it to avoid
* calling nbtk_bin_get_child() every time we need it
*/
ClutterActor *child;
ClutterActor *hscroll;
ClutterActor *vscroll;
gfloat row_size;
gfloat column_size;
gboolean row_size_set : 1;
gboolean column_size_set : 1;
guint mouse_scroll : 1;
};
enum {
PROP_0,
PROP_HSCROLL,
PROP_VSCROLL,
PROP_MOUSE_SCROLL
};
static void
nbtk_scroll_view_get_property (GObject *object, guint property_id,
GValue *value, GParamSpec *pspec)
{
NbtkScrollViewPrivate *priv = ((NbtkScrollView *)object)->priv;
switch (property_id)
{
case PROP_HSCROLL :
g_value_set_object (value, priv->hscroll);
break;
case PROP_VSCROLL :
g_value_set_object (value, priv->vscroll);
break;
case PROP_MOUSE_SCROLL:
g_value_set_boolean (value, priv->mouse_scroll);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
nbtk_scroll_view_set_property (GObject *object, guint property_id,
const GValue *value, GParamSpec *pspec)
{
switch (property_id)
{
case PROP_MOUSE_SCROLL:
nbtk_scroll_view_set_mouse_scrolling ((NbtkScrollView *) object,
g_value_get_boolean (value));
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
nbtk_scroll_view_dispose (GObject *object)
{
NbtkScrollViewPrivate *priv = NBTK_SCROLL_VIEW (object)->priv;
priv->child = NULL;
if (priv->vscroll)
{
clutter_actor_unparent (priv->vscroll);
priv->vscroll = NULL;
}
if (priv->hscroll)
{
clutter_actor_unparent (priv->hscroll);
priv->hscroll = NULL;
}
G_OBJECT_CLASS (nbtk_scroll_view_parent_class)->dispose (object);
}
static void
nbtk_scroll_view_finalize (GObject *object)
{
G_OBJECT_CLASS (nbtk_scroll_view_parent_class)->finalize (object);
}
static void
nbtk_scroll_view_paint (ClutterActor *actor)
{
NbtkScrollViewPrivate *priv = NBTK_SCROLL_VIEW (actor)->priv;
/* NbtkBin will paint the child */
CLUTTER_ACTOR_CLASS (nbtk_scroll_view_parent_class)->paint (actor);
/* paint our custom children */
if (CLUTTER_ACTOR_IS_VISIBLE (priv->hscroll))
clutter_actor_paint (priv->hscroll);
if (CLUTTER_ACTOR_IS_VISIBLE (priv->vscroll))
clutter_actor_paint (priv->vscroll);
}
static void
nbtk_scroll_view_pick (ClutterActor *actor, const ClutterColor *color)
{
NbtkScrollViewPrivate *priv = NBTK_SCROLL_VIEW (actor)->priv;
/* Chain up so we get a bounding box pained (if we are reactive) */
CLUTTER_ACTOR_CLASS (nbtk_scroll_view_parent_class)->pick (actor, color);
/* paint our custom children */
if (CLUTTER_ACTOR_IS_VISIBLE (priv->hscroll))
clutter_actor_paint (priv->hscroll);
if (CLUTTER_ACTOR_IS_VISIBLE (priv->vscroll))
clutter_actor_paint (priv->vscroll);
}
static double
get_scrollbar_width (NbtkScrollView *scroll_view)
{
ShellThemeNode *theme_node = nbtk_widget_get_theme_node (NBTK_WIDGET (scroll_view));
double result = DEFAULT_SCROLLBAR_WIDTH;
shell_theme_node_get_length (theme_node, "scrollbar-width", FALSE, &result);
return result;
}
static double
get_scrollbar_height (NbtkScrollView *scroll_view)
{
ShellThemeNode *theme_node = nbtk_widget_get_theme_node (NBTK_WIDGET (scroll_view));
double result = DEFAULT_SCROLLBAR_WIDTH;
shell_theme_node_get_length (theme_node, "scrollbar-height", FALSE, &result);
return result;
}
static void
nbtk_scroll_view_get_preferred_width (ClutterActor *actor,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
NbtkScrollViewPrivate *priv = NBTK_SCROLL_VIEW (actor)->priv;
ShellThemeNode *theme_node = nbtk_widget_get_theme_node (NBTK_WIDGET (actor));
if (!priv->child)
return;
shell_theme_node_adjust_for_height (theme_node, &for_height);
/* Our natural width is the natural width of the child */
clutter_actor_get_preferred_width (priv->child,
for_height,
NULL,
natural_width_p);
/* Add space for the scroll-bar if we can determine it will be necessary */
if ((for_height >= 0) && natural_width_p)
{
gfloat natural_height;
clutter_actor_get_preferred_height (priv->child, -1.0,
NULL,
&natural_height);
if (for_height < natural_height)
*natural_width_p += get_scrollbar_width (NBTK_SCROLL_VIEW (actor));
}
if (min_width_p)
*min_width_p = 0;
shell_theme_node_adjust_preferred_width (theme_node, min_width_p, natural_width_p);
}
static void
nbtk_scroll_view_get_preferred_height (ClutterActor *actor,
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
NbtkScrollViewPrivate *priv = NBTK_SCROLL_VIEW (actor)->priv;
ShellThemeNode *theme_node = nbtk_widget_get_theme_node (NBTK_WIDGET (actor));
if (!priv->child)
return;
shell_theme_node_adjust_for_width (theme_node, &for_width);
/* Our natural height is the natural height of the child */
clutter_actor_get_preferred_height (priv->child,
for_width,
NULL,
natural_height_p);
/* Add space for the scroll-bar if we can determine it will be necessary */
if ((for_width >= 0) && natural_height_p)
{
gfloat natural_width;
clutter_actor_get_preferred_width (priv->child, -1.0,
NULL,
&natural_width);
if (for_width < natural_width)
*natural_height_p += get_scrollbar_height (NBTK_SCROLL_VIEW (actor));
}
if (min_height_p)
*min_height_p = 0;
shell_theme_node_adjust_preferred_height (theme_node, min_height_p, natural_height_p);
}
static void
nbtk_scroll_view_allocate (ClutterActor *actor,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
ClutterActorBox content_box, child_box;
ClutterActorClass *parent_parent_class;
gfloat avail_width, avail_height, sb_width, sb_height;
NbtkScrollViewPrivate *priv = NBTK_SCROLL_VIEW (actor)->priv;
ShellThemeNode *theme_node = nbtk_widget_get_theme_node (NBTK_WIDGET (actor));
/* Chain up to the parent's parent class
*
* We do this because we do not want NbtkBin to allocate the child, as we
* give it a different allocation later, depending on whether the scrollbars
* are visible
*/
parent_parent_class
= g_type_class_peek_parent (nbtk_scroll_view_parent_class);
CLUTTER_ACTOR_CLASS (parent_parent_class)->
allocate (actor, box, flags);
shell_theme_node_get_content_box (theme_node, box, &content_box);
avail_width = content_box.x2 - content_box.x1;
avail_height = content_box.y2 - content_box.y1;
sb_width = get_scrollbar_width (NBTK_SCROLL_VIEW (actor));
sb_height = get_scrollbar_width (NBTK_SCROLL_VIEW (actor));
if (!CLUTTER_ACTOR_IS_VISIBLE (priv->vscroll))
sb_width = 0;
if (!CLUTTER_ACTOR_IS_VISIBLE (priv->hscroll))
sb_height = 0;
/* Vertical scrollbar */
if (CLUTTER_ACTOR_IS_VISIBLE (priv->vscroll))
{
child_box.x1 = content_box.x2 - sb_width;
child_box.y1 = content_box.y1;
child_box.x2 = content_box.x2;
child_box.y2 = content_box.y2 - sb_height;
clutter_actor_allocate (priv->vscroll, &child_box, flags);
}
/* Horizontal scrollbar */
if (CLUTTER_ACTOR_IS_VISIBLE (priv->hscroll))
{
child_box.x1 = content_box.x1;
child_box.y1 = content_box.y2 - sb_height;
child_box.x2 = content_box.x2 - sb_width;
child_box.y2 = content_box.y2;
clutter_actor_allocate (priv->hscroll, &child_box, flags);
}
/* Child */
child_box.x1 = content_box.x1;
child_box.y1 = content_box.y1;
child_box.x2 = content_box.x2 - sb_width;
child_box.y2 = content_box.y2 - sb_height;
if (priv->child)
clutter_actor_allocate (priv->child, &child_box, flags);
}
static void
nbtk_scroll_view_style_changed (NbtkWidget *widget)
{
NbtkScrollViewPrivate *priv = NBTK_SCROLL_VIEW (widget)->priv;
nbtk_widget_style_changed (NBTK_WIDGET (priv->hscroll));
nbtk_widget_style_changed (NBTK_WIDGET (priv->vscroll));
NBTK_WIDGET_CLASS (nbtk_scroll_view_parent_class)->style_changed (widget);
}
static gboolean
nbtk_scroll_view_scroll_event (ClutterActor *self,
ClutterScrollEvent *event)
{
NbtkScrollViewPrivate *priv = NBTK_SCROLL_VIEW (self)->priv;
gdouble lower, value, upper, step;
NbtkAdjustment *vadjustment, *hadjustment;
/* don't handle scroll events if requested not to */
if (!priv->mouse_scroll)
return FALSE;
hadjustment = nbtk_scroll_bar_get_adjustment (NBTK_SCROLL_BAR(priv->hscroll));
vadjustment = nbtk_scroll_bar_get_adjustment (NBTK_SCROLL_BAR(priv->vscroll));
switch (event->direction)
{
case CLUTTER_SCROLL_UP:
case CLUTTER_SCROLL_DOWN:
if (vadjustment)
g_object_get (vadjustment,
"lower", &lower,
"step-increment", &step,
"value", &value,
"upper", &upper,
NULL);
else
return FALSE;
break;
case CLUTTER_SCROLL_LEFT:
case CLUTTER_SCROLL_RIGHT:
if (vadjustment)
g_object_get (hadjustment,
"lower", &lower,
"step-increment", &step,
"value", &value,
"upper", &upper,
NULL);
else
return FALSE;
break;
}
switch (event->direction)
{
case CLUTTER_SCROLL_UP:
if (value == lower)
return FALSE;
else
nbtk_adjustment_set_value (vadjustment, value - step);
break;
case CLUTTER_SCROLL_DOWN:
if (value == upper)
return FALSE;
else
nbtk_adjustment_set_value (vadjustment, value + step);
break;
case CLUTTER_SCROLL_LEFT:
if (value == lower)
return FALSE;
else
nbtk_adjustment_set_value (hadjustment, value - step);
break;
case CLUTTER_SCROLL_RIGHT:
if (value == upper)
return FALSE;
else
nbtk_adjustment_set_value (hadjustment, value + step);
break;
}
return TRUE;
}
static void
nbtk_scroll_view_class_init (NbtkScrollViewClass *klass)
{
GParamSpec *pspec;
GObjectClass *object_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
NbtkWidgetClass *widget_class = NBTK_WIDGET_CLASS (klass);
g_type_class_add_private (klass, sizeof (NbtkScrollViewPrivate));
object_class->get_property = nbtk_scroll_view_get_property;
object_class->set_property = nbtk_scroll_view_set_property;
object_class->dispose= nbtk_scroll_view_dispose;
object_class->finalize = nbtk_scroll_view_finalize;
actor_class->paint = nbtk_scroll_view_paint;
actor_class->pick = nbtk_scroll_view_pick;
actor_class->get_preferred_width = nbtk_scroll_view_get_preferred_width;
actor_class->get_preferred_height = nbtk_scroll_view_get_preferred_height;
actor_class->allocate = nbtk_scroll_view_allocate;
actor_class->scroll_event = nbtk_scroll_view_scroll_event;
widget_class->style_changed = nbtk_scroll_view_style_changed;
g_object_class_install_property (object_class,
PROP_HSCROLL,
g_param_spec_object ("hscroll",
"NbtkScrollBar",
"Horizontal scroll indicator",
NBTK_TYPE_SCROLL_BAR,
G_PARAM_READABLE));
g_object_class_install_property (object_class,
PROP_VSCROLL,
g_param_spec_object ("vscroll",
"NbtkScrollBar",
"Vertical scroll indicator",
NBTK_TYPE_SCROLL_BAR,
G_PARAM_READABLE));
pspec = g_param_spec_boolean ("enable-mouse-scrolling",
"Enable Mouse Scrolling",
"Enable automatic mouse wheel scrolling",
TRUE,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_MOUSE_SCROLL,
pspec);
}
static void
child_adjustment_changed_cb (NbtkAdjustment *adjustment,
ClutterActor *bar)
{
NbtkScrollView *scroll;
gdouble lower, upper, page_size;
scroll = NBTK_SCROLL_VIEW (clutter_actor_get_parent (bar));
/* Determine if this scroll-bar should be visible */
nbtk_adjustment_get_values (adjustment, NULL,
&lower, &upper,
NULL, NULL,
&page_size);
if ((upper - lower) > page_size)
clutter_actor_show (bar);
else
clutter_actor_hide (bar);
/* Request a resize */
clutter_actor_queue_relayout (CLUTTER_ACTOR (scroll));
}
static void
child_hadjustment_notify_cb (GObject *gobject,
GParamSpec *arg1,
gpointer user_data)
{
NbtkAdjustment *hadjust;
ClutterActor *actor = CLUTTER_ACTOR (gobject);
NbtkScrollViewPrivate *priv = NBTK_SCROLL_VIEW (user_data)->priv;
hadjust = nbtk_scroll_bar_get_adjustment (NBTK_SCROLL_BAR(priv->hscroll));
if (hadjust)
g_signal_handlers_disconnect_by_func (hadjust,
child_adjustment_changed_cb,
priv->hscroll);
nbtk_scrollable_get_adjustments (NBTK_SCROLLABLE (actor), &hadjust, NULL);
if (hadjust)
{
/* Force scroll step if neede. */
if (priv->column_size_set)
{
g_object_set (hadjust,
"step-increment", priv->column_size,
NULL);
}
nbtk_scroll_bar_set_adjustment (NBTK_SCROLL_BAR(priv->hscroll), hadjust);
g_signal_connect (hadjust, "changed", G_CALLBACK (
child_adjustment_changed_cb), priv->hscroll);
child_adjustment_changed_cb (hadjust, priv->hscroll);
}
}
static void
child_vadjustment_notify_cb (GObject *gobject,
GParamSpec *arg1,
gpointer user_data)
{
NbtkAdjustment *vadjust;
ClutterActor *actor = CLUTTER_ACTOR (gobject);
NbtkScrollViewPrivate *priv = NBTK_SCROLL_VIEW (user_data)->priv;
vadjust = nbtk_scroll_bar_get_adjustment (NBTK_SCROLL_BAR(priv->vscroll));
if (vadjust)
g_signal_handlers_disconnect_by_func (vadjust,
child_adjustment_changed_cb,
priv->vscroll);
nbtk_scrollable_get_adjustments (NBTK_SCROLLABLE(actor), NULL, &vadjust);
if (vadjust)
{
/* Force scroll step if neede. */
if (priv->row_size_set)
{
g_object_set (vadjust,
"step-increment", priv->row_size,
NULL);
}
nbtk_scroll_bar_set_adjustment (NBTK_SCROLL_BAR(priv->vscroll), vadjust);
g_signal_connect (vadjust, "changed", G_CALLBACK (
child_adjustment_changed_cb), priv->vscroll);
child_adjustment_changed_cb (vadjust, priv->vscroll);
}
}
static void
nbtk_scroll_view_init (NbtkScrollView *self)
{
NbtkScrollViewPrivate *priv = self->priv = SCROLL_VIEW_PRIVATE (self);
priv->hscroll = CLUTTER_ACTOR (nbtk_scroll_bar_new (NULL));
priv->vscroll = g_object_new (NBTK_TYPE_SCROLL_BAR, "vertical", TRUE, NULL);
clutter_actor_set_parent (priv->hscroll, CLUTTER_ACTOR (self));
clutter_actor_set_parent (priv->vscroll, CLUTTER_ACTOR (self));
/* mouse scroll is enabled by default, so we also need to be reactive */
priv->mouse_scroll = TRUE;
g_object_set (G_OBJECT (self), "reactive", TRUE, NULL);
}
static void
nbtk_scroll_view_add (ClutterContainer *container,
ClutterActor *actor)
{
NbtkScrollView *self = NBTK_SCROLL_VIEW (container);
NbtkScrollViewPrivate *priv = self->priv;
if (NBTK_IS_SCROLLABLE (actor))
{
priv->child = actor;
/* chain up to NbtkBin::add() */
nbtk_scroll_view_parent_iface->add (container, actor);
/* Get adjustments for scroll-bars */
g_signal_connect (actor, "notify::hadjustment",
G_CALLBACK (child_hadjustment_notify_cb),
container);
g_signal_connect (actor, "notify::vadjustment",
G_CALLBACK (child_vadjustment_notify_cb),
container);
child_hadjustment_notify_cb (G_OBJECT (actor), NULL, container);
child_vadjustment_notify_cb (G_OBJECT (actor), NULL, container);
}
else
{
g_warning ("Attempting to add an actor of type %s to "
"a NbtkScrollView, but the actor does "
"not implement NbtkScrollable.",
g_type_name (G_OBJECT_TYPE (actor)));
}
}
static void
nbtk_scroll_view_remove (ClutterContainer *container,
ClutterActor *actor)
{
NbtkScrollViewPrivate *priv = NBTK_SCROLL_VIEW (container)->priv;
if (actor == priv->child)
{
g_object_ref (priv->child);
/* chain up to NbtkBin::remove() */
nbtk_scroll_view_parent_iface->remove (container, actor);
g_signal_handlers_disconnect_by_func (priv->child,
child_hadjustment_notify_cb,
container);
g_signal_handlers_disconnect_by_func (priv->child,
child_vadjustment_notify_cb,
container);
nbtk_scrollable_set_adjustments ((NbtkScrollable*) priv->child, NULL, NULL);
g_object_unref (priv->child);
priv->child = NULL;
}
}
static void
nbtk_scroll_view_foreach_with_internals (ClutterContainer *container,
ClutterCallback callback,
gpointer user_data)
{
NbtkScrollViewPrivate *priv = NBTK_SCROLL_VIEW (container)->priv;
if (priv->child != NULL)
callback (priv->child, user_data);
if (priv->hscroll != NULL)
callback (priv->hscroll, user_data);
if (priv->vscroll != NULL)
callback (priv->vscroll, user_data);
}
static void
clutter_container_iface_init (ClutterContainerIface *iface)
{
/* store a pointer to the NbtkBin implementation of
* ClutterContainer so that we can chain up when
* overriding the methods
*/
nbtk_scroll_view_parent_iface = g_type_interface_peek_parent (iface);
iface->add = nbtk_scroll_view_add;
iface->remove = nbtk_scroll_view_remove;
iface->foreach_with_internals = nbtk_scroll_view_foreach_with_internals;
}
NbtkWidget *
nbtk_scroll_view_new (void)
{
return g_object_new (NBTK_TYPE_SCROLL_VIEW, NULL);
}
/**
* nbtk_scroll_view_get_hscroll_bar:
* @scroll: a #NbtkScrollView
*
* Gets the horizontal scrollbar of the scrollbiew
*
* Return value: (transfer none): the horizontal #NbtkScrollbar
*/
ClutterActor *
nbtk_scroll_view_get_hscroll_bar (NbtkScrollView *scroll)
{
g_return_val_if_fail (NBTK_IS_SCROLL_VIEW (scroll), NULL);
return scroll->priv->hscroll;
}
/**
* nbtk_scroll_view_get_vscroll_bar:
* @scroll: a #NbtkScrollView
*
* Gets the vertical scrollbar of the scrollbiew
*
* Return value: (transfer none): the vertical #NbtkScrollbar
*/
ClutterActor *
nbtk_scroll_view_get_vscroll_bar (NbtkScrollView *scroll)
{
g_return_val_if_fail (NBTK_IS_SCROLL_VIEW (scroll), NULL);
return scroll->priv->vscroll;
}
gfloat
nbtk_scroll_view_get_column_size (NbtkScrollView *scroll)
{
NbtkAdjustment *adjustment;
gdouble column_size;
g_return_val_if_fail (scroll, 0);
adjustment = nbtk_scroll_bar_get_adjustment (
NBTK_SCROLL_BAR (scroll->priv->hscroll));
g_object_get (adjustment,
"step-increment", &column_size,
NULL);
return column_size;
}
void
nbtk_scroll_view_set_column_size (NbtkScrollView *scroll,
gfloat column_size)
{
NbtkAdjustment *adjustment;
g_return_if_fail (scroll);
if (column_size < 0)
{
scroll->priv->column_size_set = FALSE;
scroll->priv->column_size = -1;
}
else
{
scroll->priv->column_size_set = TRUE;
scroll->priv->column_size = column_size;
adjustment = nbtk_scroll_bar_get_adjustment (
NBTK_SCROLL_BAR (scroll->priv->hscroll));
if (adjustment)
g_object_set (adjustment,
"step-increment", (gdouble) scroll->priv->column_size,
NULL);
}
}
gfloat
nbtk_scroll_view_get_row_size (NbtkScrollView *scroll)
{
NbtkAdjustment *adjustment;
gdouble row_size;
g_return_val_if_fail (scroll, 0);
adjustment = nbtk_scroll_bar_get_adjustment (
NBTK_SCROLL_BAR (scroll->priv->vscroll));
g_object_get (adjustment,
"step-increment", &row_size,
NULL);
return row_size;
}
void
nbtk_scroll_view_set_row_size (NbtkScrollView *scroll,
gfloat row_size)
{
NbtkAdjustment *adjustment;
g_return_if_fail (scroll);
if (row_size < 0)
{
scroll->priv->row_size_set = FALSE;
scroll->priv->row_size = -1;
}
else
{
scroll->priv->row_size_set = TRUE;
scroll->priv->row_size = row_size;
adjustment = nbtk_scroll_bar_get_adjustment (
NBTK_SCROLL_BAR (scroll->priv->vscroll));
if (adjustment)
g_object_set (adjustment,
"step-increment", (gdouble) scroll->priv->row_size,
NULL);
}
}
void
nbtk_scroll_view_set_mouse_scrolling (NbtkScrollView *scroll,
gboolean enabled)
{
NbtkScrollViewPrivate *priv;
g_return_if_fail (NBTK_IS_SCROLL_VIEW (scroll));
priv = NBTK_SCROLL_VIEW (scroll)->priv;
if (priv->mouse_scroll != enabled)
{
priv->mouse_scroll = enabled;
/* make sure we can receive mouse wheel events */
if (enabled)
clutter_actor_set_reactive ((ClutterActor *) scroll, TRUE);
}
}
gboolean
nbtk_scroll_view_get_mouse_scrolling (NbtkScrollView *scroll)
{
NbtkScrollViewPrivate *priv;
g_return_val_if_fail (NBTK_IS_SCROLL_VIEW (scroll), FALSE);
priv = NBTK_SCROLL_VIEW (scroll)->priv;
return priv->mouse_scroll;
}

View File

@ -0,0 +1,87 @@
/*
* nbtk-scroll-view.h: Container with scroll-bars
*
* Copyright 2008 OpenedHand
* Copyright 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
* Written by: Chris Lord <chris@openedhand.com>
* Port to Nbtk by: Robert Staudinger <robsta@openedhand.com>
*
*/
#if !defined(NBTK_H_INSIDE) && !defined(NBTK_COMPILATION)
#error "Only <nbtk/nbtk.h> can be included directly.h"
#endif
#ifndef __NBTK_SCROLL_VIEW_H__
#define __NBTK_SCROLL_VIEW_H__
#include <nbtk/nbtk-bin.h>
G_BEGIN_DECLS
#define NBTK_TYPE_SCROLL_VIEW (nbtk_scroll_view_get_type())
#define NBTK_SCROLL_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NBTK_TYPE_SCROLL_VIEW, NbtkScrollView))
#define NBTK_IS_SCROLL_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NBTK_TYPE_SCROLL_VIEW))
#define NBTK_SCROLL_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NBTK_TYPE_SCROLL_VIEW, NbtkScrollViewClass))
#define NBTK_IS_SCROLL_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NBTK_TYPE_SCROLL_VIEW))
#define NBTK_SCROLL_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NBTK_TYPE_SCROLL_VIEW, NbtkScrollViewClass))
typedef struct _NbtkScrollView NbtkScrollView;
typedef struct _NbtkScrollViewPrivate NbtkScrollViewPrivate;
typedef struct _NbtkScrollViewClass NbtkScrollViewClass;
/**
* NbtkScrollView:
*
* The contents of this structure are private and should only be accessed
* through the public API.
*/
struct _NbtkScrollView
{
/*< private >*/
NbtkBin parent_instance;
NbtkScrollViewPrivate *priv;
};
struct _NbtkScrollViewClass
{
NbtkBinClass parent_class;
};
GType nbtk_scroll_view_get_type (void) G_GNUC_CONST;
NbtkWidget * nbtk_scroll_view_new (void);
ClutterActor * nbtk_scroll_view_get_hscroll_bar (NbtkScrollView *scroll);
ClutterActor * nbtk_scroll_view_get_vscroll_bar (NbtkScrollView *scroll);
gfloat nbtk_scroll_view_get_column_size (NbtkScrollView *scroll);
void nbtk_scroll_view_set_column_size (NbtkScrollView *scroll,
gfloat column_size);
gfloat nbtk_scroll_view_get_row_size (NbtkScrollView *scroll);
void nbtk_scroll_view_set_row_size (NbtkScrollView *scroll,
gfloat row_size);
void nbtk_scroll_view_set_mouse_scrolling (NbtkScrollView *scroll, gboolean enabled);
gboolean nbtk_scroll_view_get_mouse_scrolling (NbtkScrollView *scroll);
G_END_DECLS
#endif /* __NBTK_SCROLL_VIEW_H__ */

View File

@ -0,0 +1,96 @@
/*
* nbtk-scrollable.c: Scrollable interface
*
* Copyright 2008 OpenedHand
* Copyright 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* Written by: Chris Lord <chris@openedhand.com>
* Port to Nbtk by: Robert Staudinger <robsta@openedhand.com>
*
*/
#include "nbtk-scrollable.h"
static void
nbtk_scrollable_base_init (gpointer g_iface)
{
static gboolean initialized = FALSE;
if (!initialized)
{
g_object_interface_install_property (g_iface,
g_param_spec_object ("hadjustment",
"NbtkAdjustment",
"Horizontal adjustment",
NBTK_TYPE_ADJUSTMENT,
G_PARAM_READWRITE));
g_object_interface_install_property (g_iface,
g_param_spec_object ("vadjustment",
"NbtkAdjustment",
"Vertical adjustment",
NBTK_TYPE_ADJUSTMENT,
G_PARAM_READWRITE));
initialized = TRUE;
}
}
GType
nbtk_scrollable_get_type (void)
{
static GType type = 0;
if (type == 0)
{
static const GTypeInfo info =
{
sizeof (NbtkScrollableInterface),
nbtk_scrollable_base_init, /* base_init */
NULL,
};
type = g_type_register_static (G_TYPE_INTERFACE,
"NbtkScrollable", &info, 0);
}
return type;
}
void
nbtk_scrollable_set_adjustments (NbtkScrollable *scrollable,
NbtkAdjustment *hadjustment,
NbtkAdjustment *vadjustment)
{
NBTK_SCROLLABLE_GET_INTERFACE (scrollable)->set_adjustments (scrollable,
hadjustment,
vadjustment);
}
/**
* nbtk_scroll_bar_get_adjustments:
* @hadjustment: (transfer none) (out) (allow-none): location to store the horizontal adjustment, or %NULL
* @vadjustment: (transfer none) (out) (allow-none): location to store the vertical adjustment, or %NULL
*
* Gets the adjustment objects that store the offsets of the scrollable widget
* into its possible scrolling area.
*/
void
nbtk_scrollable_get_adjustments (NbtkScrollable *scrollable,
NbtkAdjustment **hadjustment,
NbtkAdjustment **vadjustment)
{
NBTK_SCROLLABLE_GET_INTERFACE (scrollable)->get_adjustments (scrollable,
hadjustment,
vadjustment);
}

View File

@ -0,0 +1,69 @@
/*
* nbtk-scrollable.h: Scrollable interface
*
* Copyright 2008 OpenedHand
* Copyright 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
* Written by: Chris Lord <chris@openedhand.com>
* Port to Nbtk by: Robert Staudinger <robsta@openedhand.com>
*
*/
#if !defined(NBTK_H_INSIDE) && !defined(NBTK_COMPILATION)
#error "Only <nbtk/nbtk.h> can be included directly.h"
#endif
#ifndef __NBTK_SCROLLABLE_H__
#define __NBTK_SCROLLABLE_H__
#include <glib-object.h>
#include <nbtk/nbtk-adjustment.h>
G_BEGIN_DECLS
#define NBTK_TYPE_SCROLLABLE (nbtk_scrollable_get_type ())
#define NBTK_SCROLLABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NBTK_TYPE_SCROLLABLE, NbtkScrollable))
#define NBTK_IS_SCROLLABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NBTK_TYPE_SCROLLABLE))
#define NBTK_SCROLLABLE_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), NBTK_TYPE_SCROLLABLE, NbtkScrollableInterface))
typedef struct _NbtkScrollable NbtkScrollable; /* Dummy object */
typedef struct _NbtkScrollableInterface NbtkScrollableInterface;
struct _NbtkScrollableInterface
{
GTypeInterface parent;
void (* set_adjustments) (NbtkScrollable *scrollable,
NbtkAdjustment *hadjustment,
NbtkAdjustment *vadjustment);
void (* get_adjustments) (NbtkScrollable *scrollable,
NbtkAdjustment **hadjustment,
NbtkAdjustment **vadjustment);
};
GType nbtk_scrollable_get_type (void) G_GNUC_CONST;
void nbtk_scrollable_set_adjustments (NbtkScrollable *scrollable,
NbtkAdjustment *hadjustment,
NbtkAdjustment *vadjustment);
void nbtk_scrollable_get_adjustments (NbtkScrollable *scrollable,
NbtkAdjustment **hadjustment,
NbtkAdjustment **vadjustment);
G_END_DECLS
#endif /* __NBTK_SCROLLABLE_H__ */

575
src/nbtk/nbtk-subtexture.c Normal file
View File

@ -0,0 +1,575 @@
/*
* nbtk-subtexture.h: Class to wrap a texture and "subframe" it.
* based on
* nbtk-texture-frame.c: Expandible texture actor
*
* Copyright 2007 OpenedHand
* Copyright 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <cogl/cogl.h>
#include <clutter/clutter.h>
#include "nbtk-subtexture.h"
enum
{
PROP_0,
PROP_PARENT_TEXTURE,
PROP_TOP,
PROP_LEFT,
PROP_WIDTH,
PROP_HEIGHT
};
G_DEFINE_TYPE (NbtkSubtexture, nbtk_subtexture, CLUTTER_TYPE_ACTOR);
#define NBTK_SUBTEXTURE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NBTK_TYPE_SUBTEXTURE, NbtkSubtexturePrivate))
struct _NbtkSubtexturePrivate
{
ClutterTexture *parent_texture;
int left;
int top;
int width;
int height;
CoglHandle material;
};
static void
nbtk_subtexture_get_preferred_width (ClutterActor *self,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
NbtkSubtexturePrivate *priv = NBTK_SUBTEXTURE (self)->priv;
if (G_UNLIKELY (priv->parent_texture == NULL))
{
if (min_width_p)
*min_width_p = 0;
if (natural_width_p)
*natural_width_p = 0;
}
else
{
if (min_width_p)
*min_width_p = priv->width;
if (natural_width_p)
*natural_width_p = priv->width;
}
}
static void
nbtk_subtexture_get_preferred_height (ClutterActor *self,
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
NbtkSubtexturePrivate *priv = NBTK_SUBTEXTURE (self)->priv;
if (G_UNLIKELY (priv->parent_texture == NULL))
{
if (min_height_p)
*min_height_p = 0;
if (natural_height_p)
*natural_height_p = 0;
}
else
{
if (min_height_p)
*min_height_p = priv->height;
if (natural_height_p)
*natural_height_p = priv->height;
}
}
static void
nbtk_subtexture_realize (ClutterActor *self)
{
NbtkSubtexturePrivate *priv = NBTK_SUBTEXTURE (self)->priv;
if (priv->material != COGL_INVALID_HANDLE)
return;
priv->material = cogl_material_new ();
CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
}
static void
nbtk_subtexture_unrealize (ClutterActor *self)
{
NbtkSubtexturePrivate *priv = NBTK_SUBTEXTURE (self)->priv;
if (priv->material == COGL_INVALID_HANDLE)
return;
cogl_material_unref (priv->material);
priv->material = COGL_INVALID_HANDLE;
CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
}
static void
nbtk_subtexture_paint (ClutterActor *self)
{
NbtkSubtexturePrivate *priv = NBTK_SUBTEXTURE (self)->priv;
CoglHandle cogl_texture = COGL_INVALID_HANDLE;
ClutterActorBox box = { 0, 0, 0, 0 };
gfloat tx1, ty1, tx2, ty2, tex_width, tex_height, width, height;
guint8 opacity;
/* no need to paint stuff if we don't have a texture */
if (G_UNLIKELY (priv->parent_texture == NULL))
return;
/* parent texture may have been hidden, so need to make sure it gets
* realized
*/
if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent_texture))
clutter_actor_realize (CLUTTER_ACTOR (priv->parent_texture));
cogl_texture = clutter_texture_get_cogl_texture (priv->parent_texture);
if (cogl_texture == COGL_INVALID_HANDLE)
return;
tex_width = cogl_texture_get_width (cogl_texture);
tex_height = cogl_texture_get_height (cogl_texture);
clutter_actor_get_allocation_box (self, &box);
width = box.x2 - box.x1;
height = box.y2 - box.y1;
tx1 = 1.0 * priv->left / tex_width;
ty1 = 1.0 * priv->top / tex_height;
tx2 = 1.0 * (priv->left + priv->width) / tex_width;
ty2 = 1.0 * (priv->top + priv->height) / tex_height;
opacity = clutter_actor_get_paint_opacity (self);
g_assert (priv->material != COGL_INVALID_HANDLE);
/* set the source material using the parent texture's COGL handle */
cogl_material_set_color4ub (priv->material, 255, 255, 255, opacity);
cogl_material_set_layer (priv->material, 0, cogl_texture);
cogl_set_source (priv->material);
cogl_rectangle_with_texture_coords (0,0, (float)width, (float)height,
tx1, ty1, tx2, ty2);
}
static inline void
nbtk_subtexture_set_frame_internal (NbtkSubtexture *frame,
int left,
int top,
int width,
int height)
{
NbtkSubtexturePrivate *priv = frame->priv;
GObject *gobject = G_OBJECT (frame);
gboolean changed = FALSE;
g_object_freeze_notify (gobject);
if (priv->top != top)
{
priv->top = top;
g_object_notify (gobject, "top");
changed = TRUE;
}
if (priv->left != left)
{
priv->left = left;
g_object_notify (gobject, "left");
changed = TRUE;
}
if (priv->width != width)
{
priv->width = width;
g_object_notify (gobject, "width");
changed = TRUE;
}
if (priv->height != height)
{
priv->height = height;
g_object_notify (gobject, "height");
changed = TRUE;
}
if (changed && CLUTTER_ACTOR_IS_VISIBLE (frame))
clutter_actor_queue_redraw (CLUTTER_ACTOR (frame));
g_object_thaw_notify (gobject);
}
static void
nbtk_subtexture_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
NbtkSubtexture *frame = NBTK_SUBTEXTURE (gobject);
NbtkSubtexturePrivate *priv = frame->priv;
switch (prop_id)
{
case PROP_PARENT_TEXTURE:
nbtk_subtexture_set_parent_texture (frame,
g_value_get_object (value));
break;
case PROP_TOP:
nbtk_subtexture_set_frame_internal (frame,
priv->left,
g_value_get_int (value),
priv->width,
priv->height);
break;
case PROP_LEFT:
nbtk_subtexture_set_frame_internal (frame,
g_value_get_int (value),
priv->top,
priv->width,
priv->height);
break;
case PROP_WIDTH:
nbtk_subtexture_set_frame_internal (frame,
priv->left,
priv->top,
g_value_get_int (value),
priv->height);
break;
case PROP_HEIGHT:
nbtk_subtexture_set_frame_internal (frame,
priv->left,
priv->top,
priv->width,
g_value_get_int (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
nbtk_subtexture_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
NbtkSubtexturePrivate *priv = NBTK_SUBTEXTURE (gobject)->priv;
switch (prop_id)
{
case PROP_PARENT_TEXTURE:
g_value_set_object (value, priv->parent_texture);
break;
case PROP_LEFT:
g_value_set_int (value, priv->left);
break;
case PROP_TOP:
g_value_set_int (value, priv->top);
break;
case PROP_WIDTH:
g_value_set_int (value, priv->width);
break;
case PROP_HEIGHT:
g_value_set_int (value, priv->height);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
nbtk_subtexture_dispose (GObject *gobject)
{
NbtkSubtexturePrivate *priv = NBTK_SUBTEXTURE (gobject)->priv;
if (priv->parent_texture)
{
g_object_unref (priv->parent_texture);
priv->parent_texture = NULL;
}
if (priv->material)
{
cogl_material_unref (priv->material);
priv->material = COGL_INVALID_HANDLE;
}
G_OBJECT_CLASS (nbtk_subtexture_parent_class)->dispose (gobject);
}
static void
nbtk_subtexture_class_init (NbtkSubtextureClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
GParamSpec *pspec;
g_type_class_add_private (gobject_class, sizeof (NbtkSubtexturePrivate));
actor_class->get_preferred_width =
nbtk_subtexture_get_preferred_width;
actor_class->get_preferred_height =
nbtk_subtexture_get_preferred_height;
actor_class->realize = nbtk_subtexture_realize;
actor_class->unrealize = nbtk_subtexture_unrealize;
actor_class->paint = nbtk_subtexture_paint;
gobject_class->set_property = nbtk_subtexture_set_property;
gobject_class->get_property = nbtk_subtexture_get_property;
gobject_class->dispose = nbtk_subtexture_dispose;
pspec = g_param_spec_object ("parent-texture",
"Parent Texture",
"The parent ClutterTexture",
CLUTTER_TYPE_TEXTURE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT);
g_object_class_install_property (gobject_class, PROP_PARENT_TEXTURE, pspec);
pspec = g_param_spec_int ("left",
"Left",
"Left offset",
0, G_MAXINT,
0,
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_LEFT, pspec);
pspec = g_param_spec_int ("top",
"Top",
"Top offset",
0, G_MAXINT,
0,
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_TOP, pspec);
pspec = g_param_spec_int ("width",
"Width",
"Width",
0, G_MAXINT,
0,
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_WIDTH, pspec);
pspec = g_param_spec_int ("height",
"Height",
"Height",
0, G_MAXINT,
0,
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_HEIGHT, pspec);
}
static void
nbtk_subtexture_init (NbtkSubtexture *self)
{
NbtkSubtexturePrivate *priv;
self->priv = priv = NBTK_SUBTEXTURE_GET_PRIVATE (self);
priv->material = COGL_INVALID_HANDLE;
}
/**
* nbtk_subtexture_new:
* @texture: a #ClutterTexture or %NULL
* @left: left
* @top: top
* @width: width
* @height: height
*
* A #NbtkSubtexture is a specialized texture that efficiently clones
* an area of the given @texture while keeping preserving portions of the
* same texture.
*
* A #NbtkSubtexture can be used to make a rectangular texture fit a
* given size without stretching its borders.
*
* Return value: the newly created #NbtkSubtexture
*/
ClutterActor*
nbtk_subtexture_new (ClutterTexture *texture,
gint left,
gint top,
gint width,
gint height)
{
g_return_val_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture), NULL);
return g_object_new (NBTK_TYPE_SUBTEXTURE,
"parent-texture", texture,
"top", top,
"left", left,
"width", width,
"height", height,
NULL);
}
/**
* nbtk_subtexture_get_parent_texture:
* @frame: A #NbtkSubtexture
*
* Return the texture used by the #NbtkSubtexture
*
* Returns: (transfer none): a #ClutterTexture owned by the #NbtkSubtexture
*/
ClutterTexture *
nbtk_subtexture_get_parent_texture (NbtkSubtexture *frame)
{
g_return_val_if_fail (NBTK_IS_SUBTEXTURE (frame), NULL);
return frame->priv->parent_texture;
}
/**
* nbtk_subtexture_set_parent_texture:
* @frame: A #NbtkSubtexture
* @texture: A #ClutterTexture
*
* Set the #ClutterTexture used by this #NbtkSubtexture
*
*/
void
nbtk_subtexture_set_parent_texture (NbtkSubtexture *frame,
ClutterTexture *texture)
{
NbtkSubtexturePrivate *priv;
gboolean was_visible;
g_return_if_fail (NBTK_IS_SUBTEXTURE (frame));
g_return_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture));
priv = frame->priv;
was_visible = CLUTTER_ACTOR_IS_VISIBLE (frame);
if (priv->parent_texture == texture)
return;
if (priv->parent_texture)
{
g_object_unref (priv->parent_texture);
priv->parent_texture = NULL;
if (was_visible)
clutter_actor_hide (CLUTTER_ACTOR (frame));
}
if (texture)
{
priv->parent_texture = g_object_ref (texture);
if (was_visible && CLUTTER_ACTOR_IS_VISIBLE (priv->parent_texture))
clutter_actor_show (CLUTTER_ACTOR (frame));
}
clutter_actor_queue_relayout (CLUTTER_ACTOR (frame));
g_object_notify (G_OBJECT (frame), "parent-texture");
}
/**
* nbtk_subtexture_set_frame:
* @frame: A #NbtkSubtexture
* @left: left
* @top: top
* @width: width
* @height: height
*
* Set the frame of the subtexture
*
*/
void
nbtk_subtexture_set_frame (NbtkSubtexture *frame,
gint left,
gint top,
gint width,
gint height)
{
g_return_if_fail (NBTK_IS_SUBTEXTURE (frame));
nbtk_subtexture_set_frame_internal (frame, left, top, width, height);
}
/**
* nbtk_subtexture_get_frame:
* @frame: A #NbtkSubtexture
* @left: left
* @top: top
* @width: width
* @height: height
*
* Retrieve the current frame.
*
*/
void
nbtk_subtexture_get_frame (NbtkSubtexture *frame,
gint *left,
gint *top,
gint *width,
gint *height)
{
NbtkSubtexturePrivate *priv;
g_return_if_fail (NBTK_IS_SUBTEXTURE (frame));
priv = frame->priv;
if (top)
*top = priv->top;
if (left)
*left = priv->left;
if (width)
*width = priv->width;
if (height)
*height = priv->height;
}

View File

@ -0,0 +1,92 @@
/*
* nbtk-subtexture.h: Class to wrap a texture and "subframe" it.
*
* Based on
* nbtk-texture-frame.h: Expandible texture actor
*
* Copyright 2007, 2008 OpenedHand Ltd
* Copyright 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
*/
#ifndef __NBTK_SUBTEXTURE_H__
#define __NBTK_SUBTEXTURE_H__
#include <clutter/clutter.h>
G_BEGIN_DECLS
#define NBTK_TYPE_SUBTEXTURE (nbtk_subtexture_get_type ())
#define NBTK_SUBTEXTURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NBTK_TYPE_SUBTEXTURE, NbtkSubtexture))
#define NBTK_SUBTEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NBTK_TYPE_SUBTEXTURE, NbtkSubtextureClass))
#define NBTK_IS_SUBTEXTURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NBTK_TYPE_SUBTEXTURE))
#define NBTK_IS_SUBTEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NBTK_TYPE_SUBTEXTURE))
#define NBTK_SUBTEXTURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NBTK_TYPE_SUBTEXTURE, NbtkSubtextureClass))
typedef struct _NbtkSubtexture NbtkSubtexture;
typedef struct _NbtkSubtexturePrivate NbtkSubtexturePrivate;
typedef struct _NbtkSubtextureClass NbtkSubtextureClass;
/**
* NbtkSubtexture:
*
* The contents of this structure are private and should only be accessed
* through the public API.
*/
struct _NbtkSubtexture
{
/*< private >*/
ClutterActor parent_instance;
NbtkSubtexturePrivate *priv;
};
struct _NbtkSubtextureClass
{
ClutterActorClass parent_class;
/* padding for future expansion */
void (*_nbtk_box_1) (void);
void (*_nbtk_box_2) (void);
void (*_nbtk_box_3) (void);
void (*_nbtk_box_4) (void);
};
GType nbtk_subtexture_get_type (void) G_GNUC_CONST;
ClutterActor * nbtk_subtexture_new (ClutterTexture *texture,
gint top,
gint left,
gint width,
gint height);
void nbtk_subtexture_set_parent_texture (NbtkSubtexture *frame,
ClutterTexture *texture);
ClutterTexture *nbtk_subtexture_get_parent_texture (NbtkSubtexture *frame);
void nbtk_subtexture_set_frame (NbtkSubtexture *frame,
gint top,
gint left,
gint width,
gint height);
void nbtk_subtexture_get_frame (NbtkSubtexture *frame,
gint *top,
gint *left,
gint *width,
gint *height);
G_END_DECLS
#endif /* __NBTK_SUBTEXTURE_H__ */

View File

@ -0,0 +1,456 @@
/*
* nbtk-widget.h: Base class for Nbtk actors
*
* Copyright 2007 OpenedHand
* Copyright 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
*/
/**
* SECTION:nbtk-texture-cache
* @short_description: A per-process store to cache textures
*
* #NbtkTextureCache allows an application to re-use an previously loaded
* textures.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <glib.h>
#include <glib-object.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <string.h>
#include "nbtk-texture-cache.h"
#include "nbtk-marshal.h"
#include "nbtk-private.h"
#include "nbtk-subtexture.h"
G_DEFINE_TYPE (NbtkTextureCache, nbtk_texture_cache, G_TYPE_OBJECT)
#define TEXTURE_CACHE_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), NBTK_TYPE_TEXTURE_CACHE, NbtkTextureCachePrivate))
typedef struct _NbtkTextureCachePrivate NbtkTextureCachePrivate;
struct _NbtkTextureCachePrivate
{
GHashTable *cache;
};
typedef struct FinalizedClosure
{
gchar *path;
NbtkTextureCache *cache;
} FinalizedClosure;
enum
{
PROP_0,
};
static NbtkTextureCache* __cache_singleton = NULL;
/*
* Convention: posX with a value of -1 indicates whole texture
*/
typedef struct NbtkTextureCacheItem {
char filename[256];
int width, height;
int posX, posY;
ClutterActor *ptr;
} NbtkTextureCacheItem;
static NbtkTextureCacheItem *
nbtk_texture_cache_item_new (void)
{
return g_slice_new0 (NbtkTextureCacheItem);
}
static void
nbtk_texture_cache_item_free (NbtkTextureCacheItem *item)
{
g_slice_free (NbtkTextureCacheItem, item);
}
static void
nbtk_texture_cache_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
switch (prop_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
nbtk_texture_cache_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
switch (prop_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
nbtk_texture_cache_dispose (GObject *object)
{
if (G_OBJECT_CLASS (nbtk_texture_cache_parent_class)->dispose)
G_OBJECT_CLASS (nbtk_texture_cache_parent_class)->dispose (object);
}
static void
nbtk_texture_cache_finalize (GObject *object)
{
NbtkTextureCachePrivate *priv = TEXTURE_CACHE_PRIVATE(object);
if (priv->cache)
{
g_hash_table_unref (priv->cache);
priv->cache = NULL;
}
G_OBJECT_CLASS (nbtk_texture_cache_parent_class)->finalize (object);
}
static void
nbtk_texture_cache_class_init (NbtkTextureCacheClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (NbtkTextureCachePrivate));
object_class->get_property = nbtk_texture_cache_get_property;
object_class->set_property = nbtk_texture_cache_set_property;
object_class->dispose = nbtk_texture_cache_dispose;
object_class->finalize = nbtk_texture_cache_finalize;
}
static void
nbtk_texture_cache_init (NbtkTextureCache *self)
{
NbtkTextureCachePrivate *priv = TEXTURE_CACHE_PRIVATE(self);
priv->cache = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
NULL);
}
/**
* nbtk_texture_cache_get_default:
*
* Returns the default texture cache. This is owned by Nbtk and should not be
* unreferenced or freed.
*
* Returns: (transfer none): a NbtkTextureCache
*/
NbtkTextureCache*
nbtk_texture_cache_get_default (void)
{
if (G_UNLIKELY (__cache_singleton == NULL))
__cache_singleton = g_object_new (NBTK_TYPE_TEXTURE_CACHE, NULL);
return __cache_singleton;
}
#if 0
static void
on_texure_finalized (gpointer data,
GObject *where_the_object_was)
{
FinalizedClosure *closure = (FinalizedClosure *)data;
NbtkTextureCachePrivate *priv = TEXTURE_CACHE_PRIVATE(closure->cache);
g_hash_table_remove (priv->cache, closure->path);
g_free(closure->path);
g_free(closure);
}
#endif
/**
* nbtk_texture_cache_get_size:
* @self: A #NbtkTextureCache
*
* Returns the number of items in the texture cache
*
* Returns: the current size of the cache
*/
gint
nbtk_texture_cache_get_size (NbtkTextureCache *self)
{
NbtkTextureCachePrivate *priv = TEXTURE_CACHE_PRIVATE(self);
return g_hash_table_size (priv->cache);
}
static void
add_texture_to_cache (NbtkTextureCache *self,
const gchar *path,
NbtkTextureCacheItem *item)
{
/* FinalizedClosure *closure; */
NbtkTextureCachePrivate *priv = TEXTURE_CACHE_PRIVATE(self);
g_hash_table_insert (priv->cache, g_strdup (path), item);
#if 0
/* Make sure we can remove from hash */
closure = g_new0 (FinalizedClosure, 1);
closure->path = g_strdup (path);
closure->cache = self;
g_object_weak_ref (G_OBJECT (res), on_texure_finalized, closure);
#endif
}
/* NOTE: you should unref the returned texture when not needed */
/**
* nbtk_texture_cache_get_texture:
* @self: A #NbtkTextureCache
* @path: A path to a image file
* @want_clone: ignored
*
* Create a new ClutterTexture with the specified image. Adds the image to the
* cache if the image had not been previously loaded. Subsequent calls with
* the same image path will return a new ClutterTexture with the previously
* loaded image.
*
* Returns: (transfer none): a newly created ClutterTexture
*/
ClutterTexture*
nbtk_texture_cache_get_texture (NbtkTextureCache *self,
const gchar *path,
gboolean want_clone)
{
ClutterActor *texture;
CoglHandle *handle;
NbtkTextureCachePrivate *priv;
NbtkTextureCacheItem *item;
g_return_val_if_fail (NBTK_IS_TEXTURE_CACHE (self), NULL);
g_return_val_if_fail (path != NULL, NULL);
priv = TEXTURE_CACHE_PRIVATE (self);
if (want_clone)
g_warning ("The want_clone parameter of %s is now ignored. This function "
"always returns a new ClutterTexture", __FUNCTION__);
item = g_hash_table_lookup (priv->cache, path);
if (item && item->posX != -1)
{
GError *err = NULL;
/*
* We have a cache hit, but it's for a partial texture. The only
* sane option is to read it from disk and just don't cache it
* at all.
*/
return CLUTTER_TEXTURE(clutter_texture_new_from_file(path, &err));
}
if (!item)
{
GError *err = NULL;
item = nbtk_texture_cache_item_new ();
item->posX = -1;
item->posY = -1;
item->ptr = clutter_texture_new_from_file (path, &err);
clutter_texture_get_base_size (CLUTTER_TEXTURE (item->ptr),
&item->width, &item->height);
if (!item->ptr)
{
if (err)
{
g_warning ("Error loading image: %s", err->message);
g_error_free (err);
}
return NULL;
}
add_texture_to_cache (self, path, item);
}
texture = clutter_texture_new ();
handle = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (item->ptr));
clutter_texture_set_cogl_texture ((ClutterTexture*) texture, handle);
return (ClutterTexture*) texture;
}
/**
* nbtk_texture_cache_get_actor:
* @self: A #NbtkTextureCache
* @path: A path to a image file
*
* Create a new ClutterSubTexture with the specified image. Adds the image to the
* cache if the image had not been previously loaded. Subsequent calls with
* the same image path will return a new ClutterTexture with the previously
* loaded image.
*
* Use this function if all you need is an actor for drawing.
*
* Returns: (transfer none): a newly created ClutterTexture
*/
ClutterActor*
nbtk_texture_cache_get_actor (NbtkTextureCache *self,
const gchar *path)
{
NbtkTextureCachePrivate *priv;
NbtkTextureCacheItem *item;
GError *err = NULL;
g_return_val_if_fail (NBTK_IS_TEXTURE_CACHE (self), NULL);
g_return_val_if_fail (path != NULL, NULL);
priv = TEXTURE_CACHE_PRIVATE (self);
item = g_hash_table_lookup (priv->cache, path);
if (item)
{
int posX = item->posX;
int posY = item->posY;
if (posX == -1)
posX = 0;
if (posY == -1)
posY = 0;
return nbtk_subtexture_new (CLUTTER_TEXTURE (item->ptr), posX, posY,
item->width, item->height);
}
item = nbtk_texture_cache_item_new ();
item->posX = -1;
item->posY = -1;
item->ptr = clutter_texture_new_from_file (path, &err);
clutter_texture_get_base_size (CLUTTER_TEXTURE (item->ptr),
&item->width, &item->height);
if (!item->ptr)
{
if (err)
{
g_warning ("Error loading image: %s", err->message);
g_error_free (err);
}
return NULL;
}
add_texture_to_cache (self, path, item);
return nbtk_subtexture_new (CLUTTER_TEXTURE (item->ptr), 0, 0, item->width,
item->height);
}
void
nbtk_texture_cache_load_cache (NbtkTextureCache *self,
const gchar *filename)
{
FILE *file;
NbtkTextureCacheItem *element, head;
int ret;
ClutterActor *actor;
GError *error = NULL;
NbtkTextureCachePrivate *priv;
g_return_if_fail (NBTK_IS_TEXTURE_CACHE (self));
g_return_if_fail (filename != NULL);
priv = TEXTURE_CACHE_PRIVATE (self);
file = fopen(filename, "rm");
if (!file)
return;
ret = fread (&head, sizeof(NbtkTextureCacheItem), 1, file);
if (ret < 0)
{
fclose (file);
return;
}
/* check if we already if this texture in the cache */
if (g_hash_table_lookup (priv->cache, head.filename))
{
/* skip it, we're done */
fclose (file);
return;
}
actor = clutter_texture_new_from_file (head.filename, &error);
if (error)
{
g_critical (G_STRLOC ": Error opening cache image file: %s",
error->message);
g_clear_error (&error);
fclose (file);
return;
}
element = nbtk_texture_cache_item_new ();
element->posX = -1;
element->posY = -1;
element->ptr = actor;
strncpy (element->filename, head.filename, 256);
clutter_texture_get_base_size (CLUTTER_TEXTURE (element->ptr),
&element->width, &element->height);
g_hash_table_insert (priv->cache, element->filename, element);
while (!feof (file))
{
element = nbtk_texture_cache_item_new ();
ret = fread (element, sizeof (NbtkTextureCacheItem), 1, file);
if (ret < 1)
{
/* end of file */
nbtk_texture_cache_item_free (element);
break;
}
element->ptr = actor;
if (g_hash_table_lookup (priv->cache, element->filename))
{
/* file is already in the cache.... */
nbtk_texture_cache_item_free (element);
} else {
g_hash_table_insert (priv->cache, element->filename, element);
}
}
}

View File

@ -0,0 +1,94 @@
/*
* nbtk-texture-cache.h: Cached textures object
*
* Copyright 2007 OpenedHand
* Copyright 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
*/
#if !defined(NBTK_H_INSIDE) && !defined(NBTK_COMPILATION)
#error "Only <nbtk/nbtk.h> can be included directly.h"
#endif
#ifndef _NBTK_TEXTURE_CACHE
#define _NBTK_TEXTURE_CACHE
#include <glib-object.h>
#include <clutter/clutter.h>
G_BEGIN_DECLS
#define NBTK_TYPE_TEXTURE_CACHE nbtk_texture_cache_get_type()
#define NBTK_TEXTURE_CACHE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
NBTK_TYPE_TEXTURE_CACHE, NbtkTextureCache))
#define NBTK_TEXTURE_CACHE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), \
NBTK_TYPE_TEXTURE_CACHE, NbtkTextureCacheClass))
#define NBTK_IS_TEXTURE_CACHE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
NBTK_TYPE_TEXTURE_CACHE))
#define NBTK_IS_TEXTURE_CACHE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
NBTK_TYPE_TEXTURE_CACHE))
#define NBTK_TEXTURE_CACHE_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
NBTK_TYPE_TEXTURE_CACHE, NbtkTextureCacheClass))
/**
* NbtkTextureCache:
*
* The contents of this structure are private and should only be accessed
* through the public API.
*/
typedef struct {
/*< private >*/
GObject parent;
} NbtkTextureCache;
typedef struct {
GObjectClass parent_class;
void (* loaded) (NbtkTextureCache *self,
const gchar *path,
ClutterTexture *texture);
void (* error_loading) (NbtkTextureCache *self,
GError *error);
} NbtkTextureCacheClass;
GType nbtk_texture_cache_get_type (void);
NbtkTextureCache* nbtk_texture_cache_get_default (void);
ClutterTexture* nbtk_texture_cache_get_texture (NbtkTextureCache *self,
const gchar *path,
gboolean want_clone);
ClutterActor* nbtk_texture_cache_get_actor (NbtkTextureCache *self,
const gchar *path);
gint nbtk_texture_cache_get_size (NbtkTextureCache *self);
void nbtk_texture_cache_load_cache(NbtkTextureCache *self, const char *filename);
G_END_DECLS
#endif /* _NBTK_TEXTURE_CACHE */

View File

@ -0,0 +1,620 @@
/*
* nbtk-texture-frame.h: Expandible texture actor
*
* Copyright 2007 OpenedHand
* Copyright 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
*/
/**
* SECTION:nbtk-texture-frame
* @short_description: Stretch a texture to fit the entire allocation
*
* #NbtkTextureFrame
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <cogl/cogl.h>
#include "nbtk-texture-frame.h"
#include "nbtk-private.h"
enum
{
PROP_0,
PROP_PARENT_TEXTURE,
PROP_TOP,
PROP_RIGHT,
PROP_BOTTOM,
PROP_LEFT
};
G_DEFINE_TYPE (NbtkTextureFrame, nbtk_texture_frame, CLUTTER_TYPE_ACTOR);
#define NBTK_TEXTURE_FRAME_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NBTK_TYPE_TEXTURE_FRAME, NbtkTextureFramePrivate))
struct _NbtkTextureFramePrivate
{
ClutterTexture *parent_texture;
gfloat top;
gfloat right;
gfloat bottom;
gfloat left;
};
static void
nbtk_texture_frame_get_preferred_width (ClutterActor *self,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
NbtkTextureFramePrivate *priv = NBTK_TEXTURE_FRAME (self)->priv;
if (G_UNLIKELY (priv->parent_texture == NULL))
{
if (min_width_p)
*min_width_p = 0;
if (natural_width_p)
*natural_width_p = 0;
}
else
{
ClutterActorClass *klass;
/* by directly querying the parent texture's class implementation
* we are going around any override mechanism the parent texture
* might have in place, and we ask directly for the original
* preferred width
*/
klass = CLUTTER_ACTOR_GET_CLASS (priv->parent_texture);
klass->get_preferred_width (CLUTTER_ACTOR (priv->parent_texture),
for_height,
min_width_p,
natural_width_p);
}
}
static void
nbtk_texture_frame_get_preferred_height (ClutterActor *self,
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
NbtkTextureFramePrivate *priv = NBTK_TEXTURE_FRAME (self)->priv;
if (G_UNLIKELY (priv->parent_texture == NULL))
{
if (min_height_p)
*min_height_p = 0;
if (natural_height_p)
*natural_height_p = 0;
}
else
{
ClutterActorClass *klass;
/* by directly querying the parent texture's class implementation
* we are going around any override mechanism the parent texture
* might have in place, and we ask directly for the original
* preferred height
*/
klass = CLUTTER_ACTOR_GET_CLASS (priv->parent_texture);
klass->get_preferred_height (CLUTTER_ACTOR (priv->parent_texture),
for_width,
min_height_p,
natural_height_p);
}
}
static void
nbtk_texture_frame_paint (ClutterActor *self)
{
NbtkTextureFramePrivate *priv = NBTK_TEXTURE_FRAME (self)->priv;
CoglHandle cogl_texture = COGL_INVALID_HANDLE;
CoglHandle cogl_material = COGL_INVALID_HANDLE;
ClutterActorBox box = { 0, };
gfloat width, height;
gfloat tex_width, tex_height;
gfloat ex, ey;
gfloat tx1, ty1, tx2, ty2;
guint8 opacity;
/* no need to paint stuff if we don't have a texture */
if (G_UNLIKELY (priv->parent_texture == NULL))
return;
/* parent texture may have been hidden, so need to make sure it gets
* realized
*/
if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent_texture))
clutter_actor_realize (CLUTTER_ACTOR (priv->parent_texture));
cogl_texture = clutter_texture_get_cogl_texture (priv->parent_texture);
if (cogl_texture == COGL_INVALID_HANDLE)
return;
cogl_material = clutter_texture_get_cogl_material (priv->parent_texture);
if (cogl_material == COGL_INVALID_HANDLE)
return;
tex_width = cogl_texture_get_width (cogl_texture);
tex_height = cogl_texture_get_height (cogl_texture);
clutter_actor_get_allocation_box (self, &box);
width = box.x2 - box.x1;
height = box.y2 - box.y1;
tx1 = priv->left / tex_width;
tx2 = (tex_width - priv->right) / tex_width;
ty1 = priv->top / tex_height;
ty2 = (tex_height - priv->bottom) / tex_height;
ex = width - priv->right;
if (ex < 0)
ex = priv->right; /* FIXME ? */
ey = height - priv->bottom;
if (ey < 0)
ey = priv->bottom; /* FIXME ? */
opacity = clutter_actor_get_paint_opacity (self);
/* Paint using the parent texture's material. It should already have
the cogl texture set as the first layer */
/* NB: for correct blending we need set a preumultiplied color here: */
cogl_material_set_color4ub (cogl_material,
opacity, opacity, opacity, opacity);
cogl_set_source (cogl_material);
{
GLfloat rectangles[] =
{
/* top left corner */
0, 0, priv->left, priv->top,
0.0, 0.0,
tx1, ty1,
/* top middle */
priv->left, 0, ex, priv->top,
tx1, 0.0,
tx2, ty1,
/* top right */
ex, 0, width, priv->top,
tx2, 0.0,
1.0, ty1,
/* mid left */
0, priv->top, priv->left, ey,
0.0, ty1,
tx1, ty2,
/* center */
priv->left, priv->top, ex, ey,
tx1, ty1,
tx2, ty2,
/* mid right */
ex, priv->top, width, ey,
tx2, ty1,
1.0, ty2,
/* bottom left */
0, ey, priv->left, height,
0.0, ty2,
tx1, 1.0,
/* bottom center */
priv->left, ey, ex, height,
tx1, ty2,
tx2, 1.0,
/* bottom right */
ex, ey, width, height,
tx2, ty2,
1.0, 1.0
};
cogl_rectangles_with_texture_coords (rectangles, 9);
}
}
static inline void
nbtk_texture_frame_set_frame_internal (NbtkTextureFrame *frame,
gfloat top,
gfloat right,
gfloat bottom,
gfloat left)
{
NbtkTextureFramePrivate *priv = frame->priv;
GObject *gobject = G_OBJECT (frame);
gboolean changed = FALSE;
g_object_freeze_notify (gobject);
if (priv->top != top)
{
priv->top = top;
g_object_notify (gobject, "top");
changed = TRUE;
}
if (priv->right != right)
{
priv->right = right;
g_object_notify (gobject, "right");
changed = TRUE;
}
if (priv->bottom != bottom)
{
priv->bottom = bottom;
g_object_notify (gobject, "bottom");
changed = TRUE;
}
if (priv->left != left)
{
priv->left = left;
g_object_notify (gobject, "left");
changed = TRUE;
}
if (changed && CLUTTER_ACTOR_IS_VISIBLE (frame))
clutter_actor_queue_redraw (CLUTTER_ACTOR (frame));
g_object_thaw_notify (gobject);
}
static void
nbtk_texture_frame_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
NbtkTextureFrame *frame = NBTK_TEXTURE_FRAME (gobject);
NbtkTextureFramePrivate *priv = frame->priv;
switch (prop_id)
{
case PROP_PARENT_TEXTURE:
nbtk_texture_frame_set_parent_texture (frame,
g_value_get_object (value));
break;
case PROP_TOP:
nbtk_texture_frame_set_frame_internal (frame,
g_value_get_float (value),
priv->right,
priv->bottom,
priv->left);
break;
case PROP_RIGHT:
nbtk_texture_frame_set_frame_internal (frame,
priv->top,
g_value_get_float (value),
priv->bottom,
priv->left);
break;
case PROP_BOTTOM:
nbtk_texture_frame_set_frame_internal (frame,
priv->top,
priv->right,
g_value_get_float (value),
priv->left);
break;
case PROP_LEFT:
nbtk_texture_frame_set_frame_internal (frame,
priv->top,
priv->right,
priv->bottom,
g_value_get_float (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
nbtk_texture_frame_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
NbtkTextureFramePrivate *priv = NBTK_TEXTURE_FRAME (gobject)->priv;
switch (prop_id)
{
case PROP_PARENT_TEXTURE:
g_value_set_object (value, priv->parent_texture);
break;
case PROP_LEFT:
g_value_set_float (value, priv->left);
break;
case PROP_TOP:
g_value_set_float (value, priv->top);
break;
case PROP_RIGHT:
g_value_set_float (value, priv->right);
break;
case PROP_BOTTOM:
g_value_set_float (value, priv->bottom);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
nbtk_texture_frame_dispose (GObject *gobject)
{
NbtkTextureFramePrivate *priv = NBTK_TEXTURE_FRAME (gobject)->priv;
if (priv->parent_texture)
{
g_object_unref (priv->parent_texture);
priv->parent_texture = NULL;
}
G_OBJECT_CLASS (nbtk_texture_frame_parent_class)->dispose (gobject);
}
static void
nbtk_texture_frame_class_init (NbtkTextureFrameClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
GParamSpec *pspec;
g_type_class_add_private (gobject_class, sizeof (NbtkTextureFramePrivate));
actor_class->get_preferred_width =
nbtk_texture_frame_get_preferred_width;
actor_class->get_preferred_height =
nbtk_texture_frame_get_preferred_height;
actor_class->paint = nbtk_texture_frame_paint;
gobject_class->set_property = nbtk_texture_frame_set_property;
gobject_class->get_property = nbtk_texture_frame_get_property;
gobject_class->dispose = nbtk_texture_frame_dispose;
pspec = g_param_spec_object ("parent-texture",
"Parent Texture",
"The parent ClutterTexture",
CLUTTER_TYPE_TEXTURE,
NBTK_PARAM_READWRITE |
G_PARAM_CONSTRUCT);
g_object_class_install_property (gobject_class, PROP_PARENT_TEXTURE, pspec);
pspec = g_param_spec_float ("left",
"Left",
"Left offset",
0, G_MAXFLOAT,
0,
NBTK_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_LEFT, pspec);
pspec = g_param_spec_float ("top",
"Top",
"Top offset",
0, G_MAXFLOAT,
0,
NBTK_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_TOP, pspec);
pspec = g_param_spec_float ("bottom",
"Bottom",
"Bottom offset",
0, G_MAXFLOAT,
0,
NBTK_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_BOTTOM, pspec);
pspec = g_param_spec_float ("right",
"Right",
"Right offset",
0, G_MAXFLOAT,
0,
NBTK_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_RIGHT, pspec);
}
static void
nbtk_texture_frame_init (NbtkTextureFrame *self)
{
NbtkTextureFramePrivate *priv;
self->priv = priv = NBTK_TEXTURE_FRAME_GET_PRIVATE (self);
}
/**
* nbtk_texture_frame_new:
* @texture: a #ClutterTexture or %NULL
* @left: left margin preserving its content
* @top: top margin preserving its content
* @right: right margin preserving its content
* @bottom: bottom margin preserving its content
*
* A #NbtkTextureFrame is a specialized texture that efficiently clones
* an area of the given @texture while keeping preserving portions of the
* same texture.
*
* A #NbtkTextureFrame can be used to make a rectangular texture fit a
* given size without stretching its borders.
*
* Return value: the newly created #NbtkTextureFrame
*/
ClutterActor*
nbtk_texture_frame_new (ClutterTexture *texture,
gfloat top,
gfloat right,
gfloat bottom,
gfloat left)
{
g_return_val_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture), NULL);
return g_object_new (NBTK_TYPE_TEXTURE_FRAME,
"parent-texture", texture,
"top", top,
"right", right,
"bottom", bottom,
"left", left,
NULL);
}
/**
* nbtk_texture_frame_get_parent_texture:
* @frame: A #NbtkTextureFrame
*
* Return the texture used by the #NbtkTextureFrame
*
* Returns: (transfer none): a #ClutterTexture owned by the #NbtkTextureFrame
*/
ClutterTexture *
nbtk_texture_frame_get_parent_texture (NbtkTextureFrame *frame)
{
g_return_val_if_fail (NBTK_IS_TEXTURE_FRAME (frame), NULL);
return frame->priv->parent_texture;
}
/**
* nbtk_texture_frame_set_parent_texture:
* @frame: A #NbtkTextureFrame
* @texture: A #ClutterTexture
*
* Set the #ClutterTexture used by this #NbtkTextureFrame
*
*/
void
nbtk_texture_frame_set_parent_texture (NbtkTextureFrame *frame,
ClutterTexture *texture)
{
NbtkTextureFramePrivate *priv;
gboolean was_visible;
g_return_if_fail (NBTK_IS_TEXTURE_FRAME (frame));
g_return_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture));
priv = frame->priv;
was_visible = CLUTTER_ACTOR_IS_VISIBLE (frame);
if (priv->parent_texture == texture)
return;
if (priv->parent_texture)
{
g_object_unref (priv->parent_texture);
priv->parent_texture = NULL;
if (was_visible)
clutter_actor_hide (CLUTTER_ACTOR (frame));
}
if (texture)
{
priv->parent_texture = g_object_ref_sink (texture);
if (was_visible && CLUTTER_ACTOR_IS_VISIBLE (priv->parent_texture))
clutter_actor_show (CLUTTER_ACTOR (frame));
}
clutter_actor_queue_relayout (CLUTTER_ACTOR (frame));
g_object_notify (G_OBJECT (frame), "parent-texture");
}
/**
* nbtk_texture_frame_set_frame:
* @frame: A #NbtkTextureFrame
* @top: width of the top slice
* @right: width of the right slice
* @bottom: width of the bottom slice
* @left: width of the left slice
*
* Set the slice lines of the specified frame. The slices are calculated as
* widths from the edge of the frame.
*
*/
void
nbtk_texture_frame_set_frame (NbtkTextureFrame *frame,
gfloat top,
gfloat right,
gfloat bottom,
gfloat left)
{
g_return_if_fail (NBTK_IS_TEXTURE_FRAME (frame));
nbtk_texture_frame_set_frame_internal (frame, top, right, bottom, left);
}
/**
* nbtk_texture_frame_get_frame:
* @frame: A #NbtkTextureFrame
* @top: width of the top slice
* @right: width of the right slice
* @bottom: width of the bottom slice
* @left: width of the left slice
*
* Retrieve the current slice lines from the specified frame.
*
*/
void
nbtk_texture_frame_get_frame (NbtkTextureFrame *frame,
gfloat *top,
gfloat *right,
gfloat *bottom,
gfloat *left)
{
NbtkTextureFramePrivate *priv;
g_return_if_fail (NBTK_IS_TEXTURE_FRAME (frame));
priv = frame->priv;
if (top)
*top = priv->top;
if (right)
*right = priv->right;
if (bottom)
*bottom = priv->bottom;
if (left)
*left = priv->left;
}

View File

@ -0,0 +1,92 @@
/*
* nbtk-texture-frame.h: Expandible texture actor
*
* Copyright 2007, 2008 OpenedHand Ltd
* Copyright 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
*/
#if !defined(NBTK_H_INSIDE) && !defined(NBTK_COMPILATION)
#error "Only <nbtk/nbtk.h> can be included directly.h"
#endif
#ifndef __NBTK_TEXTURE_FRAME_H__
#define __NBTK_TEXTURE_FRAME_H__
#include <clutter/clutter.h>
G_BEGIN_DECLS
#define NBTK_TYPE_TEXTURE_FRAME (nbtk_texture_frame_get_type ())
#define NBTK_TEXTURE_FRAME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NBTK_TYPE_TEXTURE_FRAME, NbtkTextureFrame))
#define NBTK_TEXTURE_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NBTK_TYPE_TEXTURE_FRAME, NbtkTextureFrameClass))
#define NBTK_IS_TEXTURE_FRAME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NBTK_TYPE_TEXTURE_FRAME))
#define NBTK_IS_TEXTURE_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NBTK_TYPE_TEXTURE_FRAME))
#define NBTK_TEXTURE_FRAME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NBTK_TYPE_TEXTURE_FRAME, NbtkTextureFrameClass))
typedef struct _NbtkTextureFrame NbtkTextureFrame;
typedef struct _NbtkTextureFramePrivate NbtkTextureFramePrivate;
typedef struct _NbtkTextureFrameClass NbtkTextureFrameClass;
/**
* NbtkTextureFrame:
*
* The contents of this structure are private and should only be accessed
* through the public API.
*/
struct _NbtkTextureFrame
{
/*< private >*/
ClutterActor parent_instance;
NbtkTextureFramePrivate *priv;
};
struct _NbtkTextureFrameClass
{
ClutterActorClass parent_class;
/* padding for future expansion */
void (*_clutter_box_1) (void);
void (*_clutter_box_2) (void);
void (*_clutter_box_3) (void);
void (*_clutter_box_4) (void);
};
GType nbtk_texture_frame_get_type (void) G_GNUC_CONST;
ClutterActor * nbtk_texture_frame_new (ClutterTexture *texture,
gfloat top,
gfloat right,
gfloat bottom,
gfloat left);
void nbtk_texture_frame_set_parent_texture (NbtkTextureFrame *frame,
ClutterTexture *texture);
ClutterTexture *nbtk_texture_frame_get_parent_texture (NbtkTextureFrame *frame);
void nbtk_texture_frame_set_frame (NbtkTextureFrame *frame,
gfloat top,
gfloat right,
gfloat bottom,
gfloat left);
void nbtk_texture_frame_get_frame (NbtkTextureFrame *frame,
gfloat *top,
gfloat *right,
gfloat *bottom,
gfloat *left);
G_END_DECLS
#endif /* __NBTK_TEXTURE_FRAME_H__ */

664
src/nbtk/nbtk-tooltip.c Normal file
View File

@ -0,0 +1,664 @@
/*
* nbtk-tooltip.c: Plain tooltip actor
*
* Copyright 2008, 2009 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
* Written by: Thomas Wood <thomas@linux.intel.com>
*
*/
/**
* SECTION:nbtk-tooltip
* @short_description: A tooltip widget
*
* #NbtkTooltip implements a single tooltip. It should not normally be created
* by the application but by the widget implementing tooltip capabilities, for
* example, #nbtk_button_set_tooltip().
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <clutter/clutter.h>
#include "nbtk-tooltip.h"
#include "nbtk-widget.h"
#include "nbtk-private.h"
enum
{
PROP_0,
PROP_LABEL,
PROP_TIP_AREA
};
#define NBTK_TOOLTIP_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), NBTK_TYPE_TOOLTIP, NbtkTooltipPrivate))
struct _NbtkTooltipPrivate
{
ClutterActor *label;
gfloat arrow_offset;
gboolean actor_below;
ClutterGeometry *tip_area;
};
G_DEFINE_TYPE (NbtkTooltip, nbtk_tooltip, NBTK_TYPE_WIDGET);
static void
nbtk_tooltip_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
NbtkTooltip *tooltip = NBTK_TOOLTIP (gobject);
switch (prop_id)
{
case PROP_LABEL:
nbtk_tooltip_set_label (tooltip, g_value_get_string (value));
break;
case PROP_TIP_AREA:
nbtk_tooltip_set_tip_area (tooltip, g_value_get_boxed (value));
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
nbtk_tooltip_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
NbtkTooltipPrivate *priv = NBTK_TOOLTIP (gobject)->priv;
switch (prop_id)
{
case PROP_LABEL:
g_value_set_string (value, clutter_text_get_text (CLUTTER_TEXT (priv->label)));
break;
case PROP_TIP_AREA:
g_value_set_boxed (value, priv->tip_area);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
nbtk_tooltip_style_changed (NbtkWidget *self)
{
NbtkTooltipPrivate *priv;
ShellThemeNode *theme_node;
ClutterColor color;
const PangoFontDescription *font;
gchar *font_string;
priv = NBTK_TOOLTIP (self)->priv;
theme_node = nbtk_widget_get_theme_node (self);
shell_theme_node_get_foreground_color (theme_node, &color);
clutter_text_set_color (CLUTTER_TEXT (priv->label), &color);
font = shell_theme_node_get_font (theme_node);
font_string = pango_font_description_to_string (font);
clutter_text_set_font_name (CLUTTER_TEXT (priv->label), font_string);
g_free (font_string);
NBTK_WIDGET_CLASS (nbtk_tooltip_parent_class)->style_changed (self);
}
static void
nbtk_tooltip_get_preferred_width (ClutterActor *self,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
NbtkTooltipPrivate *priv = NBTK_TOOLTIP (self)->priv;
ShellThemeNode *theme_node = nbtk_widget_get_theme_node (NBTK_WIDGET (self));
gfloat min_label_w, natural_label_w;
gfloat label_height, arrow_height;
ClutterActor *arrow_image;
shell_theme_node_adjust_for_height (theme_node, &for_height);
arrow_image = nbtk_widget_get_background_image (NBTK_WIDGET (self));
if (arrow_image)
{
clutter_actor_get_preferred_height (arrow_image,
-1,
NULL,
&arrow_height);
}
else
{
arrow_height = 0;
}
if (for_height > -1)
{
label_height = for_height - arrow_height;
}
else
{
label_height = -1;
}
if (priv->label)
{
clutter_actor_get_preferred_width (priv->label,
label_height,
&min_label_w,
&natural_label_w);
}
else
{
min_label_w = 0;
natural_label_w = 0;
}
shell_theme_node_adjust_preferred_width (theme_node, min_width_p, natural_width_p);
}
static void
nbtk_tooltip_get_preferred_height (ClutterActor *self,
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
NbtkTooltipPrivate *priv = NBTK_TOOLTIP (self)->priv;
ShellThemeNode *theme_node = nbtk_widget_get_theme_node (NBTK_WIDGET (self));
gfloat arrow_height;
gfloat min_label_h, natural_label_h;
ClutterActor *arrow_image;
shell_theme_node_adjust_for_width (theme_node, &for_width);
arrow_image = nbtk_widget_get_background_image (NBTK_WIDGET (self));
if (arrow_image && !priv->actor_below)
{
clutter_actor_get_preferred_height (arrow_image,
-1,
NULL,
&arrow_height);
}
else
{
arrow_height = 0;
}
if (priv->label)
{
clutter_actor_get_preferred_height (priv->label,
for_width,
&min_label_h,
&natural_label_h);
}
else
{
min_label_h = 0;
natural_label_h = 0;
}
if (min_height_p)
*min_height_p = arrow_height + min_label_h;
if (natural_height_p)
*natural_height_p = arrow_height + natural_label_h;
shell_theme_node_adjust_preferred_height (theme_node, min_height_p, natural_height_p);
}
static void
nbtk_tooltip_allocate (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
NbtkTooltipPrivate *priv = NBTK_TOOLTIP (self)->priv;
ShellThemeNode *theme_node = nbtk_widget_get_theme_node (NBTK_WIDGET (self));
ClutterActorBox content_box, child_box, arrow_box;
gfloat arrow_height, arrow_width;
ClutterActor *border_image, *arrow_image;
CLUTTER_ACTOR_CLASS (nbtk_tooltip_parent_class)->allocate (self,
box,
flags);
shell_theme_node_get_content_box (theme_node, box, &content_box);
arrow_image = nbtk_widget_get_background_image (NBTK_WIDGET (self));
if (arrow_image && !priv->actor_below)
{
clutter_actor_get_preferred_height (arrow_image, -1, NULL, &arrow_height);
clutter_actor_get_preferred_width (arrow_image, -1, NULL, &arrow_width);
arrow_box.x1 = (float) (priv->arrow_offset) - (int) (arrow_width / 2);
arrow_box.y1 = 0;
arrow_box.x2 = arrow_box.x1 + arrow_width;
arrow_box.y2 = arrow_box.y1 + arrow_height;
clutter_actor_allocate (arrow_image, &arrow_box, flags);
}
else
{
arrow_height = 0;
arrow_width = 0;
}
child_box.x1 = child_box.y1 = 0;
child_box.x2 = (box->x2 - box->x1);
child_box.y2 = (box->y2 - box->y1);
/* remove the space that is used by the arrow */
child_box.y1 += arrow_height;
border_image = nbtk_widget_get_border_image (NBTK_WIDGET (self));
if (border_image)
clutter_actor_allocate (border_image, &child_box, flags);
if (priv->label)
{
child_box = content_box;
child_box.y1 += arrow_height;
clutter_actor_allocate (priv->label, &child_box, flags);
}
}
static void
nbtk_tooltip_paint (ClutterActor *self)
{
ClutterActor *border_image, *arrow_image;
NbtkTooltipPrivate *priv = NBTK_TOOLTIP (self)->priv;
border_image = nbtk_widget_get_border_image (NBTK_WIDGET (self));
if (border_image)
clutter_actor_paint (border_image);
arrow_image = nbtk_widget_get_background_image (NBTK_WIDGET (self));
if (arrow_image && !priv->actor_below)
clutter_actor_paint (arrow_image);
clutter_actor_paint (priv->label);
}
static void
nbtk_tooltip_map (ClutterActor *self)
{
NbtkTooltipPrivate *priv = NBTK_TOOLTIP (self)->priv;
ClutterActor *border_image, *arrow_image;
CLUTTER_ACTOR_CLASS (nbtk_tooltip_parent_class)->map (self);
border_image = nbtk_widget_get_border_image (NBTK_WIDGET (self));
if (border_image)
clutter_actor_map (border_image);
arrow_image = nbtk_widget_get_background_image (NBTK_WIDGET (self));
if (arrow_image)
clutter_actor_map (arrow_image);
clutter_actor_map (priv->label);
}
static void
nbtk_tooltip_unmap (ClutterActor *self)
{
NbtkTooltipPrivate *priv = NBTK_TOOLTIP (self)->priv;
ClutterActor *border_image, *arrow_image;
CLUTTER_ACTOR_CLASS (nbtk_tooltip_parent_class)->unmap (self);
border_image = nbtk_widget_get_border_image (NBTK_WIDGET (self));
if (border_image)
clutter_actor_unmap (border_image);
arrow_image = nbtk_widget_get_background_image (NBTK_WIDGET (self));
if (arrow_image)
clutter_actor_unmap (arrow_image);
clutter_actor_unmap (priv->label);
}
static void
nbtk_tooltip_class_init (NbtkTooltipClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
NbtkWidgetClass *widget_class = NBTK_WIDGET_CLASS (klass);
GParamSpec *pspec;
g_type_class_add_private (klass, sizeof (NbtkTooltipPrivate));
gobject_class->set_property = nbtk_tooltip_set_property;
gobject_class->get_property = nbtk_tooltip_get_property;
actor_class->get_preferred_width = nbtk_tooltip_get_preferred_width;
actor_class->get_preferred_height = nbtk_tooltip_get_preferred_height;
actor_class->allocate = nbtk_tooltip_allocate;
actor_class->paint = nbtk_tooltip_paint;
actor_class->map = nbtk_tooltip_map;
actor_class->unmap = nbtk_tooltip_unmap;
widget_class->style_changed = nbtk_tooltip_style_changed;
pspec = g_param_spec_string ("label",
"Label",
"Label of the tooltip",
NULL, G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_LABEL, pspec);
pspec = g_param_spec_boxed ("tip-area",
"Tip Area",
"Area on the stage the tooltip applies to",
CLUTTER_TYPE_GEOMETRY,
NBTK_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_TIP_AREA, pspec);
}
static void
nbtk_tooltip_init (NbtkTooltip *tooltip)
{
tooltip->priv = NBTK_TOOLTIP_GET_PRIVATE (tooltip);
tooltip->priv->label = g_object_new (CLUTTER_TYPE_TEXT,
"line-alignment", PANGO_ALIGN_CENTER,
"ellipsize", PANGO_ELLIPSIZE_END,
"use-markup", TRUE,
NULL);
tooltip->priv->tip_area = NULL;
clutter_actor_set_parent (CLUTTER_ACTOR (tooltip->priv->label),
CLUTTER_ACTOR (tooltip));
g_object_set (tooltip, "show-on-set-parent", FALSE, NULL);
clutter_actor_set_reactive (CLUTTER_ACTOR (tooltip), FALSE);
}
static void
nbtk_tooltip_update_position (NbtkTooltip *tooltip)
{
NbtkTooltipPrivate *priv = tooltip->priv;
ClutterGeometry *tip_area = tooltip->priv->tip_area;
gfloat tooltip_w, tooltip_h, tooltip_x, tooltip_y;
gfloat stage_w, stage_h;
ClutterActor *stage;
/* ensure the tooltip with is not fixed size */
clutter_actor_set_size ((ClutterActor*) tooltip, -1, -1);
/* if no area set, just position ourselves top left */
if (!priv->tip_area)
{
clutter_actor_set_position ((ClutterActor*) tooltip, 0, 0);
return;
}
/* we need to have a style in case there are padding/border values to take into
* account when calculating width/height */
nbtk_widget_ensure_style ((NbtkWidget *) tooltip);
/* find out the tooltip's size */
clutter_actor_get_size ((ClutterActor*) tooltip, &tooltip_w, &tooltip_h);
/* attempt to place the tooltip */
tooltip_x = (int) (tip_area->x + (tip_area->width / 2) - (tooltip_w / 2));
tooltip_y = (int) (tip_area->y + tip_area->height);
stage = clutter_actor_get_stage ((ClutterActor *) tooltip);
if (!stage)
{
return;
}
clutter_actor_get_size (stage, &stage_w, &stage_h);
/* make sure the tooltip is not off screen vertically */
if (tooltip_w > stage_w)
{
tooltip_x = 0;
clutter_actor_set_width ((ClutterActor*) tooltip, stage_w);
}
else if (tooltip_x < 0)
{
tooltip_x = 0;
}
else if (tooltip_x + tooltip_w > stage_w)
{
tooltip_x = (int) (stage_w) - tooltip_w;
}
/* make sure the tooltip is not off screen horizontally */
if (tooltip_y + tooltip_h > stage_h)
{
priv->actor_below = TRUE;
/* re-query size as may have changed */
clutter_actor_get_preferred_height ((ClutterActor*) tooltip,
-1, NULL, &tooltip_h);
tooltip_y = tip_area->y - tooltip_h;
}
else
{
priv->actor_below = FALSE;
}
/* calculate the arrow offset */
priv->arrow_offset = tip_area->x + tip_area->width / 2 - tooltip_x;
clutter_actor_set_position ((ClutterActor*) tooltip, tooltip_x, tooltip_y);
}
/**
* nbtk_tooltip_get_label:
* @tooltip: a #NbtkTooltip
*
* Get the text displayed on the tooltip
*
* Returns: the text for the tooltip. This must not be freed by the application
*/
G_CONST_RETURN gchar *
nbtk_tooltip_get_label (NbtkTooltip *tooltip)
{
g_return_val_if_fail (NBTK_IS_TOOLTIP (tooltip), NULL);
return clutter_text_get_text (CLUTTER_TEXT (tooltip->priv->label));
}
/**
* nbtk_tooltip_set_label:
* @tooltip: a #NbtkTooltip
* @text: text to set the label to
*
* Sets the text displayed on the tooltip
*/
void
nbtk_tooltip_set_label (NbtkTooltip *tooltip,
const gchar *text)
{
NbtkTooltipPrivate *priv;
g_return_if_fail (NBTK_IS_TOOLTIP (tooltip));
priv = tooltip->priv;
clutter_text_set_text (CLUTTER_TEXT (priv->label), text);
g_object_notify (G_OBJECT (tooltip), "label");
}
/**
* nbtk_tooltip_show:
* @tooltip: a #NbtkTooltip
*
* Show the tooltip relative to the associated widget.
*/
void
nbtk_tooltip_show (NbtkTooltip *tooltip)
{
NbtkTooltipPrivate *priv;
ClutterActor *parent;
ClutterActor *stage;
ClutterActor *self = CLUTTER_ACTOR (tooltip);
ClutterAnimation *animation;
/* make sure we're not currently already animating (e.g. hiding) */
animation = clutter_actor_get_animation (CLUTTER_ACTOR (tooltip));
if (animation)
clutter_animation_completed (animation);
priv = tooltip->priv;
parent = clutter_actor_get_parent (self);
stage = clutter_actor_get_stage (self);
if (!stage)
{
g_warning ("NbtkTooltip is not on any stage.");
return;
}
/* make sure we're parented on the stage */
if (G_UNLIKELY (parent != stage))
{
g_object_ref (self);
clutter_actor_unparent (self);
clutter_actor_set_parent (self, stage);
g_object_unref (self);
parent = stage;
}
/* raise the tooltip to the top */
clutter_container_raise_child (CLUTTER_CONTAINER (stage),
CLUTTER_ACTOR (tooltip),
NULL);
nbtk_tooltip_update_position (tooltip);
/* finally show the tooltip... */
CLUTTER_ACTOR_CLASS (nbtk_tooltip_parent_class)->show (self);
/* and give it some bounce! */
g_object_set (G_OBJECT (self),
"scale-center-x", priv->arrow_offset,
"scale-center-y", (priv->actor_below) ? clutter_actor_get_height (self) : 0,
NULL);
clutter_actor_set_scale (self, 0.0, 0.0);
clutter_actor_animate (self, CLUTTER_EASE_OUT_ELASTIC,
500,
"scale-x", 1.0,
"scale-y", 1.0,
NULL);
}
static void
nbtk_tooltip_hide_complete (ClutterAnimation *animation,
ClutterActor *actor)
{
CLUTTER_ACTOR_CLASS (nbtk_tooltip_parent_class)->hide (actor);
g_signal_handlers_disconnect_by_func (actor,
nbtk_tooltip_hide_complete,
actor);
}
/**
* nbtk_tooltip_hide:
* @tooltip: a #NbtkTooltip
*
* Hide the tooltip
*/
void
nbtk_tooltip_hide (NbtkTooltip *tooltip)
{
ClutterAnimation *animation;
g_return_if_fail (NBTK_TOOLTIP (tooltip));
/* make sure we're not currently already animating (e.g. hiding) */
animation = clutter_actor_get_animation (CLUTTER_ACTOR (tooltip));
if (animation)
clutter_animation_completed (animation);
g_object_set (G_OBJECT (tooltip),
"scale-center-x", tooltip->priv->arrow_offset,
NULL);
animation =
clutter_actor_animate (CLUTTER_ACTOR (tooltip), CLUTTER_EASE_IN_SINE,
150,
"scale-x", 0.0,
"scale-y", 0.0,
NULL);
g_signal_connect (animation, "completed",
G_CALLBACK (nbtk_tooltip_hide_complete), tooltip);
}
/**
* nbtk_tooltip_set_tip_area:
* @tooltip: A #NbtkTooltip
* @area: A #ClutterGeometry
*
* Set the area on the stage that the tooltip applies to.
*/
void
nbtk_tooltip_set_tip_area (NbtkTooltip *tooltip,
const ClutterGeometry *area)
{
g_return_if_fail (NBTK_IS_TOOLTIP (tooltip));
if (tooltip->priv->tip_area)
g_boxed_free (CLUTTER_TYPE_GEOMETRY, tooltip->priv->tip_area);
tooltip->priv->tip_area = g_boxed_copy (CLUTTER_TYPE_GEOMETRY, area);
nbtk_tooltip_update_position (tooltip);
}
/**
* nbtk_tooltip_get_tip_area:
* @tooltip: A #NbtkTooltip
*
* Retrieve the area on the stage that the tooltip currently applies to
*
* Returns: the #ClutterGeometry, owned by the tooltip which must not be freed
* by the application.
*/
G_CONST_RETURN ClutterGeometry*
nbtk_tooltip_get_tip_area (NbtkTooltip *tooltip)
{
g_return_val_if_fail (NBTK_IS_TOOLTIP (tooltip), NULL);
return tooltip->priv->tip_area;
}

79
src/nbtk/nbtk-tooltip.h Normal file
View File

@ -0,0 +1,79 @@
/*
* nbtk-tooltip.h: Plain tooltip actor
*
* Copyright 2008, 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Written by: Thomas Wood <thomas@linux.intel.com>
*
*/
#if !defined(NBTK_H_INSIDE) && !defined(NBTK_COMPILATION)
#error "Only <nbtk/nbtk.h> can be included directly.h"
#endif
#ifndef __NBTK_TOOLTIP_H__
#define __NBTK_TOOLTIP_H__
G_BEGIN_DECLS
#include <nbtk/nbtk-bin.h>
#define NBTK_TYPE_TOOLTIP (nbtk_tooltip_get_type ())
#define NBTK_TOOLTIP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NBTK_TYPE_TOOLTIP, NbtkTooltip))
#define NBTK_IS_TOOLTIP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NBTK_TYPE_TOOLTIP))
#define NBTK_TOOLTIP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NBTK_TYPE_TOOLTIP, NbtkTooltipClass))
#define NBTK_IS_TOOLTIP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NBTK_TYPE_TOOLTIP))
#define NBTK_TOOLTIP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NBTK_TYPE_TOOLTIP, NbtkTooltipClass))
typedef struct _NbtkTooltip NbtkTooltip;
typedef struct _NbtkTooltipPrivate NbtkTooltipPrivate;
typedef struct _NbtkTooltipClass NbtkTooltipClass;
/**
* NbtkTooltip:
*
* The contents of this structure is private and should only be accessed using
* the provided API.
*/
struct _NbtkTooltip
{
/*< private >*/
NbtkBin parent_instance;
NbtkTooltipPrivate *priv;
};
struct _NbtkTooltipClass
{
NbtkBinClass parent_class;
};
GType nbtk_tooltip_get_type (void) G_GNUC_CONST;
G_CONST_RETURN gchar *nbtk_tooltip_get_label (NbtkTooltip *tooltip);
void nbtk_tooltip_set_label (NbtkTooltip *tooltip,
const gchar *text);
void nbtk_tooltip_show (NbtkTooltip *tooltip);
void nbtk_tooltip_hide (NbtkTooltip *tooltip);
void nbtk_tooltip_set_tip_area (NbtkTooltip *tooltip, const ClutterGeometry *area);
G_CONST_RETURN ClutterGeometry* nbtk_tooltip_get_tip_area (NbtkTooltip *tooltip);
G_END_DECLS
#endif /* __NBTK_TOOLTIP_H__ */

59
src/nbtk/nbtk-types.h Normal file
View File

@ -0,0 +1,59 @@
/*
* Copyright 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#if !defined(NBTK_H_INSIDE) && !defined(NBTK_COMPILATION)
#error "Only <nbtk/nbtk.h> can be included directly.h"
#endif
#ifndef __NBTK_TYPES_H__
#define __NBTK_TYPES_H__
#include <glib-object.h>
#include <clutter/clutter.h>
G_BEGIN_DECLS
#define NBTK_TYPE_PADDING (nbtk_padding_get_type ())
/**
* NbtkAlignment:
* @NBTK_ALIGN_TOP: align to the top (vertically)
* @NBTK_ALIGN_RIGHT: align to the right (horizontally)
* @NBTK_ALIGN_BOTTOM: align to the bottom (vertically)
* @NBTK_ALIGN_LEFT: align to the left (horizontally)
* @NBTK_ALIGN_CENTER: align to the center (horizontally or vertically)
*
* The alignment values for a #NbtkBin.
*/
typedef enum {
NBTK_ALIGN_TOP,
NBTK_ALIGN_RIGHT,
NBTK_ALIGN_BOTTOM,
NBTK_ALIGN_LEFT,
NBTK_ALIGN_CENTER
} NbtkAlignment;
typedef enum {
NBTK_ALIGN_START,
NBTK_ALIGN_MIDDLE,
NBTK_ALIGN_END
} NbtkAlign;
G_END_DECLS
#endif /* __NBTK_TYPES_H__ */

1378
src/nbtk/nbtk-widget.c Normal file

File diff suppressed because it is too large Load Diff

116
src/nbtk/nbtk-widget.h Normal file
View File

@ -0,0 +1,116 @@
/*
* nbtk-widget.h: Base class for Nbtk actors
*
* Copyright 2007 OpenedHand
* Copyright 2008, 2009 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
*/
#if !defined(NBTK_H_INSIDE) && !defined(NBTK_COMPILATION)
#error "Only <nbtk/nbtk.h> can be included directly.h"
#endif
#ifndef __NBTK_WIDGET_H__
#define __NBTK_WIDGET_H__
#include <clutter/clutter.h>
#include <nbtk/nbtk-types.h>
#include <toolkit/shell-theme.h>
#include <toolkit/shell-theme-node.h>
G_BEGIN_DECLS
#define NBTK_TYPE_WIDGET (nbtk_widget_get_type ())
#define NBTK_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NBTK_TYPE_WIDGET, NbtkWidget))
#define NBTK_IS_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NBTK_TYPE_WIDGET))
#define NBTK_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NBTK_TYPE_WIDGET, NbtkWidgetClass))
#define NBTK_IS_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NBTK_TYPE_WIDGET))
#define NBTK_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NBTK_TYPE_WIDGET, NbtkWidgetClass))
typedef struct _NbtkWidget NbtkWidget;
typedef struct _NbtkWidgetPrivate NbtkWidgetPrivate;
typedef struct _NbtkWidgetClass NbtkWidgetClass;
/**
* NbtkWidget:
*
* Base class for stylable actors. The contents of the #NbtkWidget
* structure are private and should only be accessed through the
* public API.
*/
struct _NbtkWidget
{
/*< private >*/
ClutterActor parent_instance;
NbtkWidgetPrivate *priv;
};
/**
* NbtkWidgetClass:
*
* Base class for stylable actors.
*/
struct _NbtkWidgetClass
{
/*< private >*/
ClutterActorClass parent_class;
/* vfuncs */
void (* draw_background) (NbtkWidget *self);
void (* style_changed) (NbtkWidget *self);
};
GType nbtk_widget_get_type (void) G_GNUC_CONST;
void nbtk_widget_set_style_pseudo_class (NbtkWidget *actor,
const gchar *pseudo_class);
G_CONST_RETURN gchar *nbtk_widget_get_style_pseudo_class (NbtkWidget *actor);
void nbtk_widget_set_style_class_name (NbtkWidget *actor,
const gchar *style_class);
G_CONST_RETURN gchar *nbtk_widget_get_style_class_name (NbtkWidget *actor);
void nbtk_widget_set_style (NbtkWidget *actor,
const gchar *style);
G_CONST_RETURN gchar *nbtk_widget_get_style (NbtkWidget *actor);
void nbtk_widget_set_theme (NbtkWidget *actor,
ShellTheme *theme);
ShellTheme *nbtk_widget_get_theme (NbtkWidget *actor);
void nbtk_widget_set_has_tooltip (NbtkWidget *widget, gboolean has_tooltip);
gboolean nbtk_widget_get_has_tooltip (NbtkWidget *widget);
void nbtk_widget_set_tooltip_text (NbtkWidget *widget, const gchar *text);
const gchar* nbtk_widget_get_tooltip_text (NbtkWidget *widget);
void nbtk_widget_show_tooltip (NbtkWidget *widget);
void nbtk_widget_hide_tooltip (NbtkWidget *widget);
void nbtk_widget_ensure_style (NbtkWidget *widget);
/* Only to be used by sub-classes of NbtkWidget */
void nbtk_widget_style_changed (NbtkWidget *widget);
ShellThemeNode *nbtk_widget_get_theme_node (NbtkWidget *widget);
ClutterActor *nbtk_widget_get_background_image (NbtkWidget *actor);
ClutterActor *nbtk_widget_get_border_image (NbtkWidget *actor);
void nbtk_widget_draw_background (NbtkWidget *widget);
G_END_DECLS
#endif /* __NBTK_WIDGET_H__ */

View File

@ -40,6 +40,7 @@ struct _ShellGlobal {
MutterPlugin *plugin;
ShellWM *wm;
const char *datadir;
const char *imagedir;
const char *configdir;
@ -57,6 +58,7 @@ enum {
PROP_STAGE,
PROP_WINDOW_GROUP,
PROP_WINDOW_MANAGER,
PROP_DATADIR,
PROP_IMAGEDIR,
PROP_CONFIGDIR,
};
@ -128,6 +130,9 @@ shell_global_get_property(GObject *object,
case PROP_WINDOW_MANAGER:
g_value_set_object (value, global->wm);
break;
case PROP_DATADIR:
g_value_set_string (value, global->datadir);
break;
case PROP_IMAGEDIR:
g_value_set_string (value, global->imagedir);
break;
@ -149,6 +154,7 @@ shell_global_init (ShellGlobal *global)
if (!datadir)
datadir = GNOME_SHELL_DATADIR;
global->datadir = datadir;
/* We make sure imagedir ends with a '/', since the JS won't have
* access to g_build_filename() and so will end up just
@ -254,6 +260,13 @@ shell_global_class_init (ShellGlobalClass *klass)
"Window management interface",
SHELL_TYPE_WM,
G_PARAM_READABLE));
g_object_class_install_property (gobject_class,
PROP_DATADIR,
g_param_spec_string ("datadir",
"Data directory",
"Directory containing gnome-shell data files",
NULL,
G_PARAM_READABLE));
g_object_class_install_property (gobject_class,
PROP_IMAGEDIR,
g_param_spec_string ("imagedir",

View File

@ -1,240 +0,0 @@
#include "shell-panel-window.h"
#include <gdk/gdkx.h>
#include <X11/Xlib.h>
#define PANEL_HEIGHT 25
enum {
PROP_0,
};
static void shell_panel_window_finalize (GObject *object);
static void shell_panel_window_size_request (GtkWidget *self, GtkRequisition *req);
static void shell_panel_window_size_allocate (GtkWidget *self, GtkAllocation *allocation);
static void shell_panel_window_realize (GtkWidget *self);
static void shell_panel_window_show (GtkWidget *self);
static void set_strut (ShellPanelWindow *self);
static void on_workarea_changed (ShellPanelWindow *self);
static void handle_new_workarea (ShellPanelWindow *self);
static GdkFilterReturn filter_func (GdkXEvent *xevent,
GdkEvent *event,
gpointer data);
G_DEFINE_TYPE(ShellPanelWindow, shell_panel_window, GTK_TYPE_WINDOW);
struct ShellPanelWindowPrivate {
GtkAllocation workarea;
guint width;
guint height;
Atom workarea_atom;
};
static void
shell_panel_window_class_init(ShellPanelWindowClass *klass)
{
GObjectClass *gobject_class = (GObjectClass *)klass;
GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
gobject_class->finalize = shell_panel_window_finalize;
widget_class->realize = shell_panel_window_realize;
widget_class->size_request = shell_panel_window_size_request;
widget_class->size_allocate = shell_panel_window_size_allocate;
widget_class->show = shell_panel_window_show;
}
static void shell_panel_window_init (ShellPanelWindow *self)
{
self->priv = g_new0 (ShellPanelWindowPrivate, 1);
self->priv->workarea_atom = gdk_x11_get_xatom_by_name_for_display (gdk_display_get_default (), "_NET_WORKAREA");
gtk_window_set_type_hint (GTK_WINDOW (self), GDK_WINDOW_TYPE_HINT_DOCK);
gtk_window_set_focus_on_map (GTK_WINDOW (self), FALSE);
gdk_window_add_filter (NULL, filter_func, self);
}
static void shell_panel_window_finalize (GObject *object)
{
ShellPanelWindow *self = (ShellPanelWindow*)object;
g_free (self->priv);
g_signal_handlers_destroy(object);
G_OBJECT_CLASS (shell_panel_window_parent_class)->finalize(object);
}
ShellPanelWindow* shell_panel_window_new(void) {
return (ShellPanelWindow*) g_object_new(SHELL_TYPE_PANEL_WINDOW,
"type", GTK_WINDOW_TOPLEVEL, NULL);
}
static void
set_strut (ShellPanelWindow *self)
{
long *buf;
int strut_size;
strut_size = GTK_WIDGET (self)->allocation.height;
buf = g_new0 (long, 4);
buf[0] = 0; /* left */
buf[1] = 0; /* right */
buf[2] = 0; /* top */
buf[3] = strut_size; /* bottom */
gdk_property_change (GTK_WIDGET (self)->window, gdk_atom_intern_static_string ("_NET_WM_STRUT"),
gdk_atom_intern_static_string ("CARDINAL"), 32,
GDK_PROP_MODE_REPLACE,
(guchar*) buf, 4);
g_free (buf);
}
static void
shell_panel_window_size_request (GtkWidget *widget, GtkRequisition *requisition)
{
ShellPanelWindow *self = SHELL_PANEL_WINDOW (widget);
GTK_WIDGET_CLASS (shell_panel_window_parent_class)->size_request(widget, requisition);
requisition->width = self->priv->width;
requisition->height = PANEL_HEIGHT;
}
static void
shell_panel_window_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
{
ShellPanelWindow *self = SHELL_PANEL_WINDOW (widget);
GTK_WIDGET_CLASS (shell_panel_window_parent_class)->size_allocate(widget, allocation);
if (GTK_WIDGET_REALIZED (self))
set_strut (self);
}
static void
shell_panel_window_realize (GtkWidget *widget)
{
ShellPanelWindow *self = SHELL_PANEL_WINDOW (widget);
GTK_WIDGET_CLASS (shell_panel_window_parent_class)->realize(widget);
set_strut (self);
}
static void
shell_panel_window_show (GtkWidget *widget)
{
ShellPanelWindow *self = SHELL_PANEL_WINDOW (widget);
on_workarea_changed (self);
GTK_WIDGET_CLASS (shell_panel_window_parent_class)->show(widget);
}
static void
handle_new_workarea (ShellPanelWindow *self)
{
GtkRequisition requisition;
int x, y;
int width;
int height;
int x_target, y_target;
gtk_widget_size_request (GTK_WIDGET (self), &requisition);
/* If we don't have a workarea, just use monitor */
if (self->priv->workarea.width == 0)
{
int monitor;
GdkRectangle monitor_geometry;
monitor = gdk_screen_get_monitor_at_point (gdk_screen_get_default (),
0, 0);
gdk_screen_get_monitor_geometry (gdk_screen_get_default (),
monitor, &monitor_geometry);
x = monitor_geometry.x;
y = monitor_geometry.y;
width = monitor_geometry.width;
height = monitor_geometry.height;
}
else
{
x = self->priv->workarea.x;
y = self->priv->workarea.y;
width = self->priv->workarea.width;
height = self->priv->workarea.height;
}
x_target = x;
y_target = y + height - requisition.height;
self->priv->width = width;
self->priv->height = height;
gtk_widget_set_size_request (GTK_WIDGET (self), width - x_target, PANEL_HEIGHT);
gtk_window_move (GTK_WINDOW (self), x_target, y_target);
}
static void
on_workarea_changed (ShellPanelWindow *self)
{
gulong bytes_after, nitems;
Atom type;
gint format;
guchar *data;
long *data32;
Atom workarea = gdk_x11_get_xatom_by_name_for_display (gdk_display_get_default (), "_NET_WORKAREA");
XGetWindowProperty (GDK_DISPLAY(), GDK_ROOT_WINDOW(),
workarea,
0, 4, FALSE, workarea,
&type, &format, &nitems, &bytes_after, &data);
if ((format == 32) && (nitems == 4) && (bytes_after == 0))
{
int x, y, width, height;
data32 = (long*) data;
x = data32[0];
y = data32[1];
width = data32[2];
height = data32[3];
if (x == self->priv->workarea.x && y == self->priv->workarea.y
&& width == self->priv->workarea.width
&& height == self->priv->workarea.height)
return;
self->priv->workarea.x = x;
self->priv->workarea.y = y;
self->priv->workarea.width = width;
self->priv->workarea.height = height;
handle_new_workarea (self);
}
else if (nitems == 0)
{
/* We have no workarea set; assume there are no other panels at this time */
self->priv->workarea.x = self->priv->workarea.y = 0;
self->priv->workarea.width = self->priv->workarea.height = 0;
handle_new_workarea (self);
}
else
{
g_printerr ("unexpected return from XGetWindowProperty: %d %ld %ld\n",
format, nitems, bytes_after);
}
}
static GdkFilterReturn
filter_func (GdkXEvent *gdk_xevent,
GdkEvent *event,
gpointer data)
{
ShellPanelWindow *self = SHELL_PANEL_WINDOW (data);
GdkFilterReturn ret = GDK_FILTER_CONTINUE;
XEvent *xevent = (XEvent *) event;
switch (xevent->type)
{
case PropertyNotify:
{
if (xevent->xproperty.atom != self->priv->workarea_atom)
break;
on_workarea_changed (self);
}
break;
default:
break;
}
return ret;
}

View File

@ -1,35 +0,0 @@
#ifndef __SHELL_PANEL_WINDOW_H__
#define __SHELL_PANEL_WINDOW_H__
#include <gtk/gtk.h>
#define SHELL_TYPE_PANEL_WINDOW (shell_panel_window_get_type ())
#define SHELL_PANEL_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_PANEL_WINDOW, ShellPanelWindow))
#define SHELL_PANEL_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_PANEL_WINDOW, ShellPanelWindowClass))
#define SHELL_IS_PANEL_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_PANEL_WINDOW))
#define SHELL_IS_PANEL_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_PANEL_WINDOW))
#define SHELL_PANEL_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_PANEL_WINDOW, ShellPanelWindowClass))
typedef struct _ShellPanelWindow ShellPanelWindow;
typedef struct _ShellPanelWindowClass ShellPanelWindowClass;
typedef struct ShellPanelWindowPrivate ShellPanelWindowPrivate;
struct _ShellPanelWindow
{
GtkWindow parent;
ShellPanelWindowPrivate *priv;
};
struct _ShellPanelWindowClass
{
GtkWindowClass parent_class;
};
GType shell_panel_window_get_type (void) G_GNUC_CONST;
ShellPanelWindow* shell_panel_window_new(void);
#endif /* __SHELL_PANEL_WINDOW_H__ */

View File

@ -0,0 +1,92 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#include <config.h>
#include "shell-border-image.h"
struct _ShellBorderImage {
GObject parent;
char *filename;
int border_top;
int border_right;
int border_bottom;
int border_left;
};
struct _ShellBorderImageClass {
GObjectClass parent_class;
};
G_DEFINE_TYPE (ShellBorderImage, shell_border_image, G_TYPE_OBJECT)
static void
shell_border_image_finalize (GObject *object)
{
ShellBorderImage *image = SHELL_BORDER_IMAGE (object);
g_free (image->filename);
G_OBJECT_CLASS (shell_border_image_parent_class)->finalize (object);
}
static void
shell_border_image_class_init (ShellBorderImageClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = shell_border_image_finalize;
}
static void
shell_border_image_init (ShellBorderImage *image)
{
}
ShellBorderImage *
shell_border_image_new (const char *filename,
int border_top,
int border_right,
int border_bottom,
int border_left)
{
ShellBorderImage *image;
image = g_object_new (SHELL_TYPE_BORDER_IMAGE, NULL);
image->filename = g_strdup (filename);
image->border_top = border_top;
image->border_right = border_right;
image->border_bottom = border_bottom;
image->border_left = border_left;
return image;
}
const char *
shell_border_image_get_filename (ShellBorderImage *image)
{
g_return_val_if_fail (SHELL_IS_BORDER_IMAGE (image), NULL);
return image->filename;
}
void
shell_border_image_get_borders (ShellBorderImage *image,
int *border_top,
int *border_right,
int *border_bottom,
int *border_left)
{
g_return_if_fail (SHELL_IS_BORDER_IMAGE (image));
if (border_top)
*border_top = image->border_top;
if (border_right)
*border_right = image->border_right;
if (border_bottom)
*border_bottom = image->border_bottom;
if (border_left)
*border_left = image->border_left;
}

View File

@ -0,0 +1,38 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#ifndef __SHELL_BORDER_IMAGE_H__
#define __SHELL_BORDER_IMAGE_H__
#include <glib-object.h>
G_BEGIN_DECLS
/* A ShellBorderImage encapsulates an image with specified unscaled borders on each edge.
*/
typedef struct _ShellBorderImage ShellBorderImage;
typedef struct _ShellBorderImageClass ShellBorderImageClass;
#define SHELL_TYPE_BORDER_IMAGE (shell_border_image_get_type ())
#define SHELL_BORDER_IMAGE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SHELL_TYPE_BORDER_IMAGE, ShellBorderImage))
#define SHELL_BORDER_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_BORDER_IMAGE, ShellBorderImageClass))
#define SHELL_IS_BORDER_IMAGE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), SHELL_TYPE_BORDER_IMAGE))
#define SHELL_IS_BORDER_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_BORDER_IMAGE))
#define SHELL_BORDER_IMAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_BORDER_IMAGE, ShellBorderImageClass))
GType shell_border_image_get_type (void) G_GNUC_CONST;
ShellBorderImage *shell_border_image_new (const char *filename,
int border_top,
int border_right,
int border_bottom,
int border_left);
const char *shell_border_image_get_filename (ShellBorderImage *image);
void shell_border_image_get_borders (ShellBorderImage *image,
int *border_top,
int *border_right,
int *border_bottom,
int *border_left);
G_END_DECLS
#endif /* __SHELL_BORDER_IMAGE_H__ */

View File

@ -0,0 +1,218 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#include <config.h>
#include "shell-theme.h"
#include "shell-theme-context.h"
struct _ShellThemeContext {
GObject parent;
double resolution;
PangoFontDescription *font;
ShellThemeNode *root_node;
ShellTheme *theme;
};
struct _ShellThemeContextClass {
GObjectClass parent_class;
};
enum
{
CHANGED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0, };
G_DEFINE_TYPE (ShellThemeContext, shell_theme_context, G_TYPE_OBJECT)
static void
shell_theme_context_finalize (GObject *object)
{
ShellThemeContext *context = SHELL_THEME_CONTEXT (object);
if (context->root_node)
g_object_unref (context->root_node);
if (context->theme)
g_object_unref (context->theme);
pango_font_description_free (context->font);
G_OBJECT_CLASS (shell_theme_context_parent_class)->finalize (object);
}
static void
shell_theme_context_class_init (ShellThemeContextClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = shell_theme_context_finalize;
signals[CHANGED] =
g_signal_new ("changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0, /* no default handler slot */
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static void
shell_theme_context_init (ShellThemeContext *context)
{
context->resolution = 96.;
context->font = pango_font_description_from_string ("sans-serif 10");
}
ShellThemeContext *
shell_theme_context_new (void)
{
ShellThemeContext *context;
context = g_object_new (SHELL_TYPE_THEME_CONTEXT, NULL);
return context;
}
static void
on_stage_destroy (ClutterStage *stage)
{
ShellThemeContext *context = shell_theme_context_get_for_stage (stage);
g_object_set_data (G_OBJECT (stage), "shell-theme-context", NULL);
g_object_unref (context);
}
/**
* shell_theme_context_get_for_stage:
* @stage: a #ClutterStage
*
* Gets a singleton theme context associated with the stage.
*
* Return value: (transfer none): the singleton theme context for the stage
*/
ShellThemeContext *
shell_theme_context_get_for_stage (ClutterStage *stage)
{
ShellThemeContext *context;
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
context = g_object_get_data (G_OBJECT (stage), "shell-theme-context");
if (context)
return context;
context = shell_theme_context_new ();
g_object_set_data (G_OBJECT (stage), "shell-theme-context", context);
g_signal_connect (stage, "destroy",
G_CALLBACK (on_stage_destroy), NULL);
return context;
}
/**
* shell_theme_context_set_theme:
* @context: a #ShellThemeContext
*
* Sets the default set of theme stylesheets for the context. This theme will
* be used for the root node and for nodes descending from it, unless some other
* style is explicitely specified.
*/
void
shell_theme_context_set_theme (ShellThemeContext *context,
ShellTheme *theme)
{
g_return_if_fail (SHELL_IS_THEME_CONTEXT (context));
g_return_if_fail (theme == NULL || SHELL_IS_THEME (theme));
if (context->theme != theme)
{
if (context->theme)
g_object_unref (context->theme);
context->theme = theme;
if (context->theme)
g_object_ref (context->theme);
g_signal_emit (context, signals[CHANGED], 0);
}
}
/**
* shell_theme_context_get_theme:
* @context: a #ShellThemeContext
*
* Gets the default theme for the context. See shell_theme_context_set_theme()
*
* Return value: (transfer none): the default theme for the context
*/
ShellTheme *
shell_theme_context_get_theme (ShellThemeContext *context)
{
g_return_val_if_fail (SHELL_IS_THEME_CONTEXT (context), NULL);
return context->theme;
}
void
shell_theme_context_set_resolution (ShellThemeContext *context,
double resolution)
{
g_return_if_fail (SHELL_IS_THEME_CONTEXT (context));
context->resolution = resolution;
}
double
shell_theme_context_get_resolution (ShellThemeContext *context)
{
g_return_val_if_fail (SHELL_IS_THEME_CONTEXT (context), 96.);
return context->resolution;
}
void
shell_theme_context_set_font (ShellThemeContext *context,
const PangoFontDescription *font)
{
g_return_if_fail (SHELL_IS_THEME_CONTEXT (context));
if (context->font == font)
return;
pango_font_description_free (context->font);
context->font = pango_font_description_copy (font);
}
const PangoFontDescription *
shell_theme_context_get_font (ShellThemeContext *context)
{
g_return_val_if_fail (SHELL_IS_THEME_CONTEXT (context), NULL);
return context->font;
}
/**
* shell_theme_context_get_root_node:
* @context: a #ShellThemeContext
*
* Gets the root node of the tree of theme style nodes that associated with this
* context. For the node tree associated with a stage, this node represents
* styles applied to the stage itself.
*
* Return value: (transfer none): the root node of the context's style tree
*/
ShellThemeNode *
shell_theme_context_get_root_node (ShellThemeContext *context)
{
if (context->root_node == NULL)
context->root_node = shell_theme_node_new (context, NULL, context->theme,
G_TYPE_NONE, NULL, NULL, NULL, NULL);
return context->root_node;
}

View File

@ -0,0 +1,40 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#ifndef __SHELL_THEME_CONTEXT_H__
#define __SHELL_THEME_CONTEXT_H__
#include <clutter/clutter.h>
#include <pango/pango.h>
#include "shell-theme-node.h"
G_BEGIN_DECLS
typedef struct _ShellThemeContextClass ShellThemeContextClass;
#define SHELL_TYPE_THEME_CONTEXT (shell_theme_context_get_type ())
#define SHELL_THEME_CONTEXT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SHELL_TYPE_THEME_CONTEXT, ShellThemeContext))
#define SHELL_THEME_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_THEME_CONTEXT, ShellThemeContextClass))
#define SHELL_IS_THEME_CONTEXT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), SHELL_TYPE_THEME_CONTEXT))
#define SHELL_IS_THEME_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_THEME_CONTEXT))
#define SHELL_THEME_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_THEME_CONTEXT, ShellThemeContextClass))
GType shell_theme_context_get_type (void) G_GNUC_CONST;
ShellThemeContext *shell_theme_context_new (void);
ShellThemeContext *shell_theme_context_get_for_stage (ClutterStage *stage);
void shell_theme_context_set_theme (ShellThemeContext *context,
ShellTheme *theme);
ShellTheme * shell_theme_context_get_theme (ShellThemeContext *context);
void shell_theme_context_set_resolution (ShellThemeContext *context,
gdouble resolution);
double shell_theme_context_get_resolution (ShellThemeContext *context);
void shell_theme_context_set_font (ShellThemeContext *context,
const PangoFontDescription *font);
const PangoFontDescription *shell_theme_context_get_font (ShellThemeContext *context);
ShellThemeNode * shell_theme_context_get_root_node (ShellThemeContext *context);
G_END_DECLS
#endif /* __SHELL_THEME_CONTEXT_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,143 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#ifndef __SHELL_THEME_NODE_H__
#define __SHELL_THEME_NODE_H__
#include <clutter/clutter.h>
#include "shell-border-image.h"
G_BEGIN_DECLS
typedef struct _ShellTheme ShellTheme;
typedef struct _ShellThemeContext ShellThemeContext;
typedef struct _ShellThemeNode ShellThemeNode;
typedef struct _ShellThemeNodeClass ShellThemeNodeClass;
#define SHELL_TYPE_THEME_NODE (shell_theme_node_get_type ())
#define SHELL_THEME_NODE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SHELL_TYPE_THEME_NODE, ShellThemeNode))
#define SHELL_THEME_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_THEME_NODE, ShellThemeNodeClass))
#define SHELL_IS_THEME_NODE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), SHELL_TYPE_THEME_NODE))
#define SHELL_IS_THEME_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_THEME_NODE))
#define SHELL_THEME_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_THEME_NODE, ShellThemeNodeClass))
typedef enum {
SHELL_SIDE_TOP,
SHELL_SIDE_RIGHT,
SHELL_SIDE_BOTTOM,
SHELL_SIDE_LEFT
} ShellSide;
typedef enum {
SHELL_CORNER_TOPLEFT,
SHELL_CORNER_TOPRIGHT,
SHELL_CORNER_BOTTOMRIGHT,
SHELL_CORNER_BOTTOMLEFT
} ShellCorner;
/* These are the CSS values; that doesn't mean we have to implement blink... */
typedef enum {
SHELL_TEXT_DECORATION_UNDERLINE = 1 << 0,
SHELL_TEXT_DECORATION_OVERLINE = 1 << 1,
SHELL_TEXT_DECORATION_LINE_THROUGH = 1 << 2,
SHELL_TEXT_DECORATION_BLINK = 1 << 3
} ShellTextDecoration;
GType shell_theme_node_get_type (void) G_GNUC_CONST;
/* An element_type of G_TYPE_NONE means this style was created for the stage
* actor and matches a selector element name of 'stage'
*/
ShellThemeNode *shell_theme_node_new (ShellThemeContext *context,
ShellThemeNode *parent_node, /* can be null */
ShellTheme *theme, /* can be null */
GType element_type,
const char *element_id,
const char *element_class,
const char *pseudo_class,
const char *inline_style);
ShellThemeNode *shell_theme_node_get_parent (ShellThemeNode *node);
ShellTheme *shell_theme_node_get_theme (ShellThemeNode *node);
GType shell_theme_node_get_element_type (ShellThemeNode *node);
const char *shell_theme_node_get_element_id (ShellThemeNode *node);
const char *shell_theme_node_get_element_class (ShellThemeNode *node);
const char *shell_theme_node_get_pseudo_class (ShellThemeNode *node);
/* Generic getters ... these are not cached so are less efficient. The other
* reason for adding the more specific version is that we can handle the
* details of the actual CSS rules, which can be complicated, especially
* for fonts
*/
gboolean shell_theme_node_get_color (ShellThemeNode *node,
const char *property_name,
gboolean inherit,
ClutterColor *color);
gboolean shell_theme_node_get_double (ShellThemeNode *node,
const char *property_name,
gboolean inherit,
double *value);
/* The length here is already resolved to pixels
*/
gboolean shell_theme_node_get_length (ShellThemeNode *node,
const char *property_name,
gboolean inherit,
gdouble *length);
/* Specific getters for particular properties: cached
*/
void shell_theme_node_get_background_color (ShellThemeNode *node,
ClutterColor *color);
void shell_theme_node_get_foreground_color (ShellThemeNode *node,
ClutterColor *color);
const char *shell_theme_node_get_background_image (ShellThemeNode *node);
double shell_theme_node_get_border_width (ShellThemeNode *node,
ShellSide side);
double shell_theme_node_get_border_radius (ShellThemeNode *node,
ShellCorner corner);
void shell_theme_node_get_border_color (ShellThemeNode *node,
ShellSide side,
ClutterColor *color);
double shell_theme_node_get_padding (ShellThemeNode *node,
ShellSide side);
ShellTextDecoration shell_theme_node_get_text_decoration (ShellThemeNode *node);
/* Font rule processing is pretty complicated, so we just hardcode it
* under the standard font/font-family/font-size/etc names. This means
* you can't have multiple separate styled fonts for a single item,
* but that should be OK.
*/
const PangoFontDescription *shell_theme_node_get_font (ShellThemeNode *node);
ShellBorderImage *shell_theme_node_get_border_image (ShellThemeNode *node);
/* Helpers for get_preferred_width()/get_preferred_height() ClutterActor vfuncs */
void shell_theme_node_adjust_for_height (ShellThemeNode *node,
float *for_height);
void shell_theme_node_adjust_preferred_width (ShellThemeNode *node,
float *min_width_p,
float *natural_width_p);
void shell_theme_node_adjust_for_width (ShellThemeNode *node,
float *for_width);
void shell_theme_node_adjust_preferred_height (ShellThemeNode *node,
float *min_height_p,
float *natural_height_p);
/* Helper for allocate() ClutterActor vfunc */
void shell_theme_node_get_content_box (ShellThemeNode *node,
const ClutterActorBox *actor_box,
ClutterActorBox *content_box);
gboolean shell_theme_node_geometry_equal (ShellThemeNode *node,
ShellThemeNode *other);
G_END_DECLS
#endif /* __SHELL_THEME_NODE_H__ */

View File

@ -0,0 +1,20 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#ifndef __SHELL_THEME_PRIVATE_H__
#define __SHELL_THEME_PRIVATE_H__
#include <libcroco/libcroco.h>
#include "shell-theme.h"
G_BEGIN_DECLS
GPtrArray *_shell_theme_get_matched_properties (ShellTheme *theme,
ShellThemeNode *node);
/* Resolve an URL from the stylesheet to a filename */
char *_shell_theme_resolve_url (ShellTheme *theme,
CRStyleSheet *base_stylesheet,
const char *url);
G_END_DECLS
#endif /* __SHELL_THEME_PRIVATE_H__ */

1029
src/toolkit/shell-theme.c Normal file

File diff suppressed because it is too large Load Diff

28
src/toolkit/shell-theme.h Normal file
View File

@ -0,0 +1,28 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#ifndef __SHELL_THEME_H__
#define __SHELL_THEME_H__
#include <glib-object.h>
#include "shell-theme-node.h"
G_BEGIN_DECLS
typedef struct _ShellThemeClass ShellThemeClass;
#define SHELL_TYPE_THEME (shell_theme_get_type ())
#define SHELL_THEME(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SHELL_TYPE_THEME, ShellTheme))
#define SHELL_THEME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_THEME, ShellThemeClass))
#define SHELL_IS_THEME(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), SHELL_TYPE_THEME))
#define SHELL_IS_THEME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_THEME))
#define SHELL_THEME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_THEME, ShellThemeClass))
GType shell_theme_get_type (void) G_GNUC_CONST;
ShellTheme *shell_theme_new (const char *application_stylesheet,
const char *theme_stylesheet,
const char *default_stylesheet);
G_END_DECLS
#endif /* __SHELL_THEME_H__ */

392
src/toolkit/test-theme.c Normal file
View File

@ -0,0 +1,392 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#include <clutter/clutter.h>
#include "shell-theme.h"
#include "shell-theme-context.h"
#include <math.h>
#include <string.h>
static ShellThemeNode *root;
static ShellThemeNode *group1;
static ShellThemeNode *text1;
static ShellThemeNode *text2;
static ShellThemeNode *group2;
static ShellThemeNode *text3;
static ShellThemeNode *text4;
static ShellThemeNode *group3;
static ShellThemeNode *cairo_texture;
static gboolean fail;
static const char *test;
static void
assert_font (ShellThemeNode *node,
const char *node_description,
const char *expected)
{
char *value = pango_font_description_to_string (shell_theme_node_get_font (node));
if (strcmp (expected, value) != 0)
{
g_print ("%s: %s.font: expected: %s, got: %s\n",
test, node_description, expected, value);
fail = TRUE;
}
g_free (value);
}
static char *
text_decoration_to_string (ShellTextDecoration decoration)
{
GString *result = g_string_new (NULL);
if (decoration & SHELL_TEXT_DECORATION_UNDERLINE)
g_string_append(result, " underline");
if (decoration & SHELL_TEXT_DECORATION_OVERLINE)
g_string_append(result, " overline");
if (decoration & SHELL_TEXT_DECORATION_LINE_THROUGH)
g_string_append(result, " line_through");
if (decoration & SHELL_TEXT_DECORATION_BLINK)
g_string_append(result, " blink");
if (result->len > 0)
g_string_erase (result, 0, 1);
else
g_string_append(result, "none");
return g_string_free (result, FALSE);
}
static void
assert_text_decoration (ShellThemeNode *node,
const char *node_description,
ShellTextDecoration expected)
{
ShellTextDecoration value = shell_theme_node_get_text_decoration (node);
if (expected != value)
{
char *es = text_decoration_to_string (expected);
char *vs = text_decoration_to_string (value);
g_print ("%s: %s.text-decoration: expected: %s, got: %s\n",
test, node_description, es, vs);
fail = TRUE;
g_free (es);
g_free (vs);
}
}
static void
assert_foreground_color (ShellThemeNode *node,
const char *node_description,
guint32 expected)
{
ClutterColor color;
shell_theme_node_get_foreground_color (node, &color);
guint32 value = clutter_color_to_pixel (&color);
if (expected != value)
{
g_print ("%s: %s.color: expected: #%08x, got: #%08x\n",
test, node_description, expected, value);
fail = TRUE;
}
}
static void
assert_background_color (ShellThemeNode *node,
const char *node_description,
guint32 expected)
{
ClutterColor color;
shell_theme_node_get_background_color (node, &color);
guint32 value = clutter_color_to_pixel (&color);
if (expected != value)
{
g_print ("%s: %s.background-color: expected: #%08x, got: #%08x\n",
test, node_description, expected, value);
fail = TRUE;
}
}
static const char *
side_to_string (ShellSide side)
{
switch (side)
{
case SHELL_SIDE_TOP:
return "top";
case SHELL_SIDE_RIGHT:
return "right";
case SHELL_SIDE_BOTTOM:
return "bottom";
case SHELL_SIDE_LEFT:
return "left";
}
return "<unknown>";
}
static void
assert_border_color (ShellThemeNode *node,
const char *node_description,
ShellSide side,
guint32 expected)
{
ClutterColor color;
shell_theme_node_get_border_color (node, side, &color);
guint32 value = clutter_color_to_pixel (&color);
if (expected != value)
{
g_print ("%s: %s.border-%s-color: expected: #%08x, got: #%08x\n",
test, node_description, side_to_string (side), expected, value);
fail = TRUE;
}
}
static void
assert_background_image (ShellThemeNode *node,
const char *node_description,
const char *expected)
{
const char *value = shell_theme_node_get_background_image (node);
if (expected == NULL)
expected = "(null)";
if (value == NULL)
value = "(null)";
if (strcmp (expected, value) != 0)
{
g_print ("%s: %s.background-image: expected: %s, got: %s\n",
test, node_description, expected, value);
fail = TRUE;
}
}
#define LENGTH_EPSILON 0.001
static void
assert_length (const char *node_description,
const char *property_description,
double expected,
double value)
{
if (fabs (expected - value) > LENGTH_EPSILON)
{
g_print ("%s %s.%s: expected: %3f, got: %3f\n",
test, node_description, property_description, expected, value);
fail = TRUE;
}
}
static void
test_defaults (void)
{
test = "defaults";
/* font comes from context */
assert_font (root, "stage", "sans-serif 12");
/* black is the default foreground color */
assert_foreground_color (root, "stage", 0x00000ff);
}
static void
test_lengths (void)
{
test = "lengths";
/* 12pt == 16px at 96dpi */
assert_length ("group1", "padding-top", 16.,
shell_theme_node_get_padding (group1, SHELL_SIDE_TOP));
/* 12px == 12px */
assert_length ("group1", "padding-right", 12.,
shell_theme_node_get_padding (group1, SHELL_SIDE_RIGHT));
/* 2em == 32px (with a 12pt font) */
assert_length ("group1", "padding-bottom", 32.,
shell_theme_node_get_padding (group1, SHELL_SIDE_BOTTOM));
/* 1in == 72pt == 96px, at 96dpi */
assert_length ("group1", "padding-left", 96.,
shell_theme_node_get_padding (group1, SHELL_SIDE_LEFT));
}
static void
test_classes (void)
{
test = "classes";
/* .special-text class overrides size and style;
* the ClutterTexture.special-text selector doesn't match */
assert_font (text1, "text1", "sans-serif Italic 32px");
}
static void
test_type_inheritance (void)
{
test = "type_inheritance";
/* From ClutterTexture element selector */
assert_length ("cairoTexture", "padding-top", 10.,
shell_theme_node_get_padding (cairo_texture, SHELL_SIDE_TOP));
/* From ClutterCairoTexture element selector */
assert_length ("cairoTexture", "padding-right", 20.,
shell_theme_node_get_padding (cairo_texture, SHELL_SIDE_RIGHT));
}
static void
test_adjacent_selector (void)
{
test = "adjacent_selector";
/* #group1 > #text1 matches text1 */
assert_foreground_color (text1, "text1", 0x00ff00ff);
/* stage > #text2 doesn't match text2 */
assert_foreground_color (text2, "text2", 0x000000ff);
}
static void
test_padding (void)
{
test = "padding";
/* Test that a 4-sided padding property assigns the right paddings to
* all sides */
assert_length ("group2", "padding-top", 1.,
shell_theme_node_get_padding (group2, SHELL_SIDE_TOP));
assert_length ("group2", "padding-right", 2.,
shell_theme_node_get_padding (group2, SHELL_SIDE_RIGHT));
assert_length ("group2", "padding-bottom", 3.,
shell_theme_node_get_padding (group2, SHELL_SIDE_BOTTOM));
assert_length ("group2", "padding-left", 4.,
shell_theme_node_get_padding (group2, SHELL_SIDE_LEFT));
}
static void
test_border (void)
{
test = "border";
/* group2 is defined as having a thin black border along the top three
* sides with rounded joins, then a square-joined green border at the
* botttom
*/
assert_length ("group2", "border-top-width", 2.,
shell_theme_node_get_border_width (group2, SHELL_SIDE_TOP));
assert_length ("group2", "border-right-width", 2.,
shell_theme_node_get_border_width (group2, SHELL_SIDE_RIGHT));
assert_length ("group2", "border-bottom-width", 5.,
shell_theme_node_get_border_width (group2, SHELL_SIDE_BOTTOM));
assert_length ("group2", "border-left-width", 2.,
shell_theme_node_get_border_width (group2, SHELL_SIDE_LEFT));
assert_border_color (group2, "group2", SHELL_SIDE_TOP, 0x000000ff);
assert_border_color (group2, "group2", SHELL_SIDE_RIGHT, 0x000000ff);
assert_border_color (group2, "group2", SHELL_SIDE_BOTTOM, 0x0000ffff);
assert_border_color (group2, "group2", SHELL_SIDE_LEFT, 0x000000ff);
assert_length ("group2", "border-radius-topleft", 10.,
shell_theme_node_get_border_radius (group2, SHELL_CORNER_TOPLEFT));
assert_length ("group2", "border-radius-topright", 10.,
shell_theme_node_get_border_radius (group2, SHELL_CORNER_TOPRIGHT));
assert_length ("group2", "border-radius-bottomright", 0.,
shell_theme_node_get_border_radius (group2, SHELL_CORNER_BOTTOMRIGHT));
assert_length ("group2", "border-radius-bottomleft", 0.,
shell_theme_node_get_border_radius (group2, SHELL_CORNER_BOTTOMLEFT));
}
static void
test_background (void)
{
test = "background";
/* group1 has a background: shortcut property setting color and image */
assert_background_color (group1, "group1", 0xff0000ff);
assert_background_image (group1, "group1", "toolkit/some-background.png");
/* text1 inherits the background image but not the color */
assert_background_color (text1, "text1", 0x00000000);
assert_background_image (text1, "text1", "toolkit/some-background.png");
/* text1 inherits inherits both, but then background: none overrides both */
assert_background_color (text2, "text2", 0x00000000);
assert_background_image (text2, "text2", NULL);
/* background-image property */
assert_background_image (group2, "group2", "toolkit/other-background.png");
}
static void
test_font (void)
{
test = "font";
/* font specified with font: */
assert_font (group2, "group2", "serif Italic 12px");
/* text3 inherits and overrides individually properties */
assert_font (text3, "text3", "serif Bold Oblique Small-Caps 24px");
}
static void
test_pseudo_class (void)
{
test = "pseudo_class";
/* text4 has :visited and :hover pseudo-classes, so should pick up both of these */
assert_foreground_color (text4, "text4", 0x888888ff);
assert_text_decoration (text4, "text4", SHELL_TEXT_DECORATION_UNDERLINE);
/* :hover pseudo-class matches, but class doesn't match */
assert_text_decoration (group3, "group3", 0);
}
static void
test_inline_style (void)
{
test = "inline_style";
/* These properties come from the inline-style specified when creating the node */
assert_foreground_color (text3, "text3", 0x00000ffff);
assert_length ("text3", "padding-bottom", 12.,
shell_theme_node_get_padding (text3, SHELL_SIDE_BOTTOM));
}
int
main (int argc, char **argv)
{
ShellTheme *theme;
ShellThemeContext *context;
clutter_init (&argc, &argv);
theme = shell_theme_new ("toolkit/test-theme.css",
NULL, NULL);
context = shell_theme_context_new ();
shell_theme_context_set_theme (context, theme);
shell_theme_context_set_resolution (context, 96.);
shell_theme_context_set_font (context,
pango_font_description_from_string ("sans-serif 12"));
root = shell_theme_context_get_root_node (context);
group1 = shell_theme_node_new (context, root, NULL,
CLUTTER_TYPE_GROUP, "group1", NULL, NULL, NULL);
text1 = shell_theme_node_new (context, group1, NULL,
CLUTTER_TYPE_TEXT, "text1", "special-text", NULL, NULL);
text2 = shell_theme_node_new (context, group1, NULL,
CLUTTER_TYPE_TEXT, "text2", NULL, NULL, NULL);
group2 = shell_theme_node_new (context, root, NULL,
CLUTTER_TYPE_GROUP, "group2", NULL, NULL, NULL);
text3 = shell_theme_node_new (context, group2, NULL,
CLUTTER_TYPE_TEXT, "text3", NULL, NULL,
"color: #0000ff; padding-bottom: 12px;");
text4 = shell_theme_node_new (context, group2, NULL,
CLUTTER_TYPE_TEXT, "text4", NULL, "visited hover", NULL);
group3 = shell_theme_node_new (context, group2, NULL,
CLUTTER_TYPE_GROUP, "group3", NULL, "hover", NULL);
cairo_texture = shell_theme_node_new (context, root, NULL,
CLUTTER_TYPE_CAIRO_TEXTURE, "cairoTexture", NULL, NULL, NULL);
test_defaults ();
test_lengths ();
test_classes ();
test_type_inheritance ();
test_adjacent_selector ();
test_padding ();
test_border ();
test_background ();
test_font ();
test_pseudo_class ();
test_inline_style ();
return fail ? 1 : 0;
}

View File

@ -0,0 +1,73 @@
stage {
}
#group1 {
padding: 12pt;
padding-right: 12px;
padding-bottom: 2em;
padding-left: 1in;
background: #ff0000 url('some-background.png');
}
#text1 {
background-image: inherit;
}
.special-text {
font-size: 24pt;
font-style: italic;
}
ClutterTexture.special-text {
font-weight: bold;
}
#text2 {
background: inherit;
background: none; /* also overrides the color */
}
#group2 {
font: italic 12px serif;
}
#text3 {
font-variant: small-caps;
font-weight: bold;
font-style: oblique;
font-size: 200%;
}
ClutterTexture {
padding: 10px;
}
ClutterCairoTexture {
padding-right: 20px;
}
#group1 > #text1 {
color: #00ff00;
}
stage > #text2 {
color: #ff0000;
}
#group2 {
background-image: url('other-background.png');
padding: 1px 2px 3px 4px;
border: 2px solid #000000;
border-bottom: 5px solid #0000ff;
border-radius: 10px 10px 0px 0px;
}
ClutterText:hover {
text-decoration: underline;
}
ClutterText:visited {
color: #888888;
}

21
tests/Makefile.am Normal file
View File

@ -0,0 +1,21 @@
noinst_SCRIPTS = run-test.sh
EXTRA_DIST = run-test.sh.in
TEST_JS = \
testcommon/ui.js \
interactive/box-layout.js
EXTRA_DIST += $(TEST_JS)
TEST_MISC = \
testcommon/test.css
EXTRA_DIST += $(TEST_MISC)
# We substitute in bindir so it works as an autostart
# file when built in a non-system prefix
run-test.sh: run-test.sh.in
$(AM_V_GEN) sed \
-e "s|@GJS_JS_DIR[@]|$(GJS_JS_DIR)|" \
-e "s|@GJS_JS_NATIVE_DIR[@]|$(GJS_JS_NATIVE_DIR)|" \
-e "s|@MUTTER_LIB_DIR[@]|$(MUTTER_LIB_DIR)|" \
-e "s|@srcdir[@]|$(srcdir)|" \
$< > $@ && chmod a+x $@

View File

@ -0,0 +1,63 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Nbtk = imports.gi.Nbtk;
const UI = imports.testcommon.ui;
UI.init();
let stage = Clutter.Stage.get_default();
stage.width = 600;
stage.height = 700;
let vbox = new Nbtk.BoxLayout({ vertical: true,
width: stage.width,
height: stage.height,
spacing: 20,
style: 'padding: 10px; background: #ffee88;' });
stage.add_actor(vbox);
vbox.add(new Nbtk.Label({ text: "Hello World",
style: 'border: 1px solid black; '
+ 'padding: 5px;' }));
vbox.add(new Nbtk.Label({ text: "Hello Round World",
style: 'border: 3px solid green; '
+ 'border-radius: 8px; '
+ 'padding: 5px;' }));
vbox.add(new Nbtk.Label({ text: "Hello Background",
style: 'border: 3px solid green; '
+ 'border-radius: 8px; '
+ 'background: white; '
+ 'padding: 5px;' }));
vbox.add(new Nbtk.Label({ text: "Border, Padding, Content: 20px" }));
let b1 = new Nbtk.BoxLayout({ vertical: true,
style: 'border: 20px solid black; '
+ 'background: white; '
+ 'padding: 20px;' });
vbox.add(b1);
b1.add(new Nbtk.BoxLayout({ width: 20, height: 20,
style: 'background: black' }));
vbox.add(new Nbtk.Label({ text: "Translucent blue border, with rounding",
style: 'border: 20px solid rgba(0, 0, 255, 0.2); '
+ 'border-radius: 10px; '
+ 'background: white; '
+ 'padding: 10px;' }));
vbox.add(new Nbtk.Label({ text: "Transparent border",
style: 'border: 20px solid transparent; '
+ 'background: white; '
+ 'padding: 10px;' }));
vbox.add(new Nbtk.Label({ text: "Border Image",
style_class: "border-image",
style: "padding: 10px;" }));
stage.show();
Clutter.main();
stage.destroy();

View File

@ -0,0 +1,87 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Nbtk = imports.gi.Nbtk;
const UI = imports.testcommon.ui;
UI.init();
let stage = Clutter.Stage.get_default();
let vbox = new Nbtk.BoxLayout({ vertical: true,
width: stage.width,
height: stage.height,
spacing: 10,
style: 'padding: 10px' });
stage.add_actor(vbox);
////////////////////////////////////////////////////////////////////////////////
let colored_boxes = new Nbtk.BoxLayout({ vertical: true,
width: 200,
height: 200,
style: 'border: 2px solid black;' });
vbox.add(colored_boxes, { x_fill: false,
x_align: Nbtk.Align.MIDDLE });
let b2 = new Nbtk.BoxLayout({ style: 'border: 2px solid #666666' });
colored_boxes.add(b2, { expand: true });
b2.add(new Nbtk.Label({ text: "Expand",
style: 'border: 1px solid #aaaaaa; '
+ 'background: #ffeecc' }),
{ expand: true });
b2.add(new Nbtk.Label({ text: "Expand\nNo Fill",
style: 'border: 1px solid #aaaaaa; '
+ 'background: #ccffaa' }),
{ expand: true,
x_fill: false,
x_align: Nbtk.Align.MIDDLE,
y_fill: false,
y_align: Nbtk.Align.MIDDLE });
colored_boxes.add(new Nbtk.Label({ text: "Default",
style: 'border: 1px solid #aaaaaa; '
+ 'background: #cceeff' }));
////////////////////////////////////////////////////////////////////////////////
function createCollapsableBox(width) {
let b = new Nbtk.BoxLayout({ width: width,
style: 'border: 1px solid black;'
+ 'font: 13px Sans;' });
b.add(new Nbtk.Label({ text: "Very Very Very Long",
style: 'background: #ffaacc;'
+ 'padding: 5px; '
+ 'border: 1px solid #666666;' }),
{ expand: true });
b.add(new Nbtk.Label({ text: "Very Very Long",
style: 'background: #ffeecc; '
+ 'padding: 5px; '
+ 'border: 1px solid #666666;' }),
{ expand: true });
b.add(new Nbtk.Label({ text: "Very Long",
style: 'background: #ccffaa; '
+ 'padding: 5px; '
+ 'border: 1px solid #666666;' }),
{ expand: true });
b.add(new Nbtk.Label({ text: "Short",
style: 'background: #cceeff; '
+ 'padding: 5px; '
+ 'border: 1px solid #666666;' }),
{ expand: true });
return b;
}
for (let width = 200; width <= 500; width += 60 ) {
vbox.add(createCollapsableBox (width),
{ x_fill: false,
x_align: Nbtk.Align.MIDDLE });
}
////////////////////////////////////////////////////////////////////////////////
stage.show();
Clutter.main();

View File

@ -0,0 +1,39 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Nbtk = imports.gi.Nbtk;
const UI = imports.testcommon.ui;
UI.init();
let stage = Clutter.Stage.get_default();
let b = new Nbtk.BoxLayout({ vertical: true,
width: stage.width,
height: stage.height });
stage.add_actor(b);
let t;
t = new Nbtk.Label({ "text": "Bold", style_class: "bold" });
b.add(t);
t = new Nbtk.Label({ "text": "Monospace", style_class: "monospace" });
b.add(t);
t = new Nbtk.Label({ "text": "Italic", style_class: "italic" });
b.add(t);
t = new Nbtk.Label({ "text": "Bold Italic", style_class: "bold italic" });
b.add(t);
t = new Nbtk.Label({ "text": "Big Italic", style_class: "big italic" });
b.add(t);
t = new Nbtk.Label({ "text": "Big Bold", style_class: "big bold" });
b.add(t);
let b2 = new Nbtk.BoxLayout({ vertical: true, style_class: "monospace" });
b.add(b2);
t = new Nbtk.Label({ "text": "Big Monospace", style_class: "big" });
b2.add(t);
t = new Nbtk.Label({ "text": "Italic Monospace", style_class: "italic" });
b2.add(t);
stage.show();
Clutter.main();

View File

@ -0,0 +1,47 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Nbtk = imports.gi.Nbtk;
const UI = imports.testcommon.ui;
UI.init();
let stage = Clutter.Stage.get_default();
let vbox = new Nbtk.BoxLayout({ vertical: true,
width: stage.width,
height: stage.height });
stage.add_actor(vbox);
let hbox = new Nbtk.BoxLayout({ spacing: 12 });
vbox.add(hbox);
let text = new Nbtk.Label({ text: "Styled Text" });
vbox.add (text);
let size = 24;
function update_size() {
text.style = 'font-size: ' + size + 'pt';
}
update_size();
let button;
button = new Nbtk.Button ({ label: 'Smaller' });
hbox.add (button);
button.connect('clicked', function() {
size /= 1.2;
update_size ();
});
button = new Nbtk.Button ({ label: 'Bigger' });
hbox.add (button);
button.connect('clicked', function() {
size *= 1.2;
update_size ();
});
stage.show();
Clutter.main();
stage.destroy();

View File

@ -0,0 +1,41 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Nbtk = imports.gi.Nbtk;
const UI = imports.testcommon.ui;
UI.init();
let stage = Clutter.Stage.get_default();
let vbox = new Nbtk.BoxLayout({ vertical: true,
width: stage.width,
height: stage.height,
style: "padding: 10px;" });
stage.add_actor(vbox);
let v = new Nbtk.ScrollView();
vbox.add(v, { expand: true });
let b = new Nbtk.BoxLayout({ vertical: true,
style: "border: 2px solid #880000; border-radius: 10px; padding: 0px 5px;" });
v.add_actor(b);
let cc_a = "a".charCodeAt(0);
let s = "";
for (let i = 0; i < 26 * 3; i++) {
s += String.fromCharCode(cc_a + i % 26);
let t = new Nbtk.Label({ text: s,
reactive: true });
let line = i + 1;
t.connect('button-press-event',
function() {
log("Click on line " + line);
});
b.add(t);
}
stage.show();
Clutter.main();
stage.destroy();

48
tests/run-test.sh.in Normal file
View File

@ -0,0 +1,48 @@
#!/bin/sh
usage() {
echo >&2 "Usage run-test.sh [-v|--verbose] <test_js>..."
exit 1
}
tests=
verbose=false
debug=
for arg in $@ ; do
case $arg in
-g|--debug)
debug="gdb --args"
;;
-v|--verbose)
verbose=true
;;
-*)
usage
;;
*)
tests="$tests $arg"
;;
esac
done
builddir=`dirname $0`
builddir=`cd $builddir && pwd`
srcdir=$builddir/@srcdir@
srcdir=`cd $srcdir && pwd`
GI_TYPELIB_PATH="@MUTTER_LIB_DIR@/mutter:$builddir/../src"
GJS_DEBUG_OUTPUT=stderr
$verbose || GJS_DEBUG_TOPICS="JS ERROR;JS LOG"
GNOME_SHELL_TESTSDIR="$srcdir/"
LD_PRELOAD="$builddir/../src/.libs/libgnome-shell.so"
export GI_TYPELIB_PATH GJS_DEBUG_OUTPUT GJS_DEBUG_TOPICS GNOME_SHELL_JS GNOME_SHELL_TESTSDIR LD_PRELOAD
gjs_args=
for i in $srcdir $srcdir/../js @GJS_JS_DIR@ @GJS_JS_NATIVE_DIR@ ; do
gjs_args="$gjs_args -I $i"
done
for test in $tests ; do
$debug gjs-console $gjs_args $test || exit $?
done

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 B

53
tests/testcommon/test.css Normal file
View File

@ -0,0 +1,53 @@
@import "../../data/theme/gnome-shell.css";
stage {
font: 16pt serif;
}
.red {
background-color: red;
}
.green {
background-color: green;
}
.blue {
background-color: blue;
}
.bold {
font-weight: bold;
}
.italic {
font-style: italic;
}
.big {
font-size: 150%;
}
.monospace {
font-family: monospace;
}
.border-image {
border: 15px;
border-image: url('border-image.png') 16;
}
NbtkButton {
background: #eeddbb;
border: 1px solid black;
border-radius: 8px;
padding: 5px;
}
NbtkButton:hover {
background: #ffeecc;
}
NbtkButton:active {
background: #ccbb99;
}

19
tests/testcommon/ui.js Normal file
View File

@ -0,0 +1,19 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const Nbtk = imports.gi.Nbtk;
const Shell = imports.gi.Shell;
const Environment = imports.ui.environment;
function init() {
Clutter.init(null, null);
Environment.init();
let stage = Clutter.Stage.get_default();
let context = Shell.ThemeContext.get_for_stage (stage);
let stylesheetPath = GLib.getenv("GNOME_SHELL_TESTSDIR") + "/testcommon/test.css";
let theme = new Shell.Theme ({ application_stylesheet: stylesheetPath });
context.set_theme (theme);
}

View File

@ -7,6 +7,8 @@
href="git://git.clutter-project.org/"/>
<repository type="git" name="git.gnome.org"
href="git://git.gnome.org/"/>
<repository type="git" name="git.moblin.org"
href="git://git.moblin.org"/>
<autotools id="gobject-introspection">
<branch repo="git.gnome.org" module="gobject-introspection"/>
@ -36,6 +38,13 @@
</dependencies>
</autotools>
<autotools id="clutter-imcontext">
<branch repo="git.moblin.org" module="clutter-imcontext"/>
<dependencies>
<dep package="clutter"/>
</dependencies>
</autotools>
<autotools id="gconf" autogenargs="--disable-defaults-service">
<branch repo="git.gnome.org" module="gconf"/>
</autotools>