Compare commits
79 Commits
2.27.2
...
nbtk-intro
Author | SHA1 | Date | |
---|---|---|---|
4f070317d2 | |||
661100abe8 | |||
3e90b11cfb | |||
4b4a1be420 | |||
1a4861ec4f | |||
2ac82da232 | |||
8f7e6f8117 | |||
d2b98701be | |||
faeda5dc8b | |||
70cb8e180b | |||
2232a92ba8 | |||
4743a8e750 | |||
e1390c7dd5 | |||
49ba54820c | |||
8ffa161a7f | |||
0eca3efcb0 | |||
9c3af62dc4 | |||
db0c2b5959 | |||
98215f497d | |||
9dbafe156e | |||
277dd7106a | |||
431f299756 | |||
d8d7f5f711 | |||
a07af9fb14 | |||
f1f11f1e76 | |||
c60a6a49de | |||
6687054474 | |||
60819b3a79 | |||
3e265b4bc6 | |||
e2aa2a00f0 | |||
1edc88a2bd | |||
271e4ca07e | |||
9f79296276 | |||
471006ba67 | |||
98bd590a5d | |||
9d88a13d3c | |||
159690b2d3 | |||
8a2bfd0e55 | |||
2ddc7cf00f | |||
04f10ceb4e | |||
ceefc5eea4 | |||
9feda69888 | |||
33f9895d71 | |||
2812c21322 | |||
7ac9fb2dd0 | |||
05c99241d6 | |||
9fb8dad80c | |||
004ad86e9d | |||
02c65fab8d | |||
dfe16f4af6 | |||
e52cb3c213 | |||
6e31e59b57 | |||
458778bcfd | |||
d8cabbee0b | |||
3029a4086b | |||
5598de6543 | |||
913aeae166 | |||
dddad9e1b5 | |||
4bfa68d209 | |||
42e3a93c20 | |||
05812ef7f9 | |||
a0df412deb | |||
678a88dbdb | |||
5e944c9a3b | |||
b28b60b47b | |||
16caa74386 | |||
470c65d046 | |||
ef6ea078dd | |||
37ee16b34d | |||
5880b3b0ed | |||
80a5f78eb2 | |||
4b727ef40d | |||
d0d79c5b3e | |||
0882da0a71 | |||
25410a730e | |||
22c445cffc | |||
42bf91fdc4 | |||
7f88e02a26 | |||
d540af847a |
2
.gitignore
vendored
2
.gitignore
vendored
@ -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
|
||||
|
17
Makefile.am
17
Makefile.am
@ -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 ; \
|
||||
|
@ -1,4 +1,4 @@
|
||||
AC_INIT(gnome-shell, 2.27.2)
|
||||
AC_INIT(gnome-shell, 2.27.3)
|
||||
|
||||
AC_CONFIG_AUX_DIR(config)
|
||||
|
||||
@ -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
|
||||
])
|
||||
|
@ -12,17 +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 \
|
||||
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
|
||||
|
||||
|
@ -1,6 +1,21 @@
|
||||
<gconfschemafile>
|
||||
<schemalist>
|
||||
|
||||
<schema>
|
||||
<key>/schemas/desktop/gnome/shell/development_tools</key>
|
||||
<applyto>/desktop/gnome/shell/development_tools</applyto>
|
||||
<owner>gnome-shell</owner>
|
||||
<type>bool</type>
|
||||
<default>true</default>
|
||||
<locale name="C">
|
||||
<short>Enable internal tools useful for developers and testers from Alt-F2</short>
|
||||
<long>
|
||||
Allows access to internal debugging and monitoring tools using
|
||||
the Alt-F2 dialog.
|
||||
</long>
|
||||
</locale>
|
||||
</schema>
|
||||
|
||||
<schema>
|
||||
<key>/schemas/desktop/gnome/shell/app_monitor/enable_monitoring</key>
|
||||
<applyto>/desktop/gnome/shell/app_monitor/enable_monitoring</applyto>
|
||||
|
97
data/theme/gnome-shell.css
Normal file
97
data/theme/gnome-shell.css
Normal 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;
|
||||
}
|
BIN
data/theme/scroll-button-down-hover.png
Normal file
BIN
data/theme/scroll-button-down-hover.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 225 B |
BIN
data/theme/scroll-button-down.png
Normal file
BIN
data/theme/scroll-button-down.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 225 B |
BIN
data/theme/scroll-button-up-hover.png
Normal file
BIN
data/theme/scroll-button-up-hover.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 211 B |
BIN
data/theme/scroll-button-up.png
Normal file
BIN
data/theme/scroll-button-up.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 211 B |
BIN
data/theme/scroll-vhandle.png
Normal file
BIN
data/theme/scroll-vhandle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 323 B |
@ -9,6 +9,7 @@ dist_jsui_DATA = \
|
||||
dash.js \
|
||||
dnd.js \
|
||||
docDisplay.js \
|
||||
environment.js \
|
||||
genericDisplay.js \
|
||||
link.js \
|
||||
lookingGlass.js \
|
||||
|
@ -36,8 +36,6 @@ function AltTabPopup() {
|
||||
|
||||
AltTabPopup.prototype = {
|
||||
_init : function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
this.actor = new Big.Box({ background_color : POPUP_BG_COLOR,
|
||||
corner_radius: POPUP_GRID_SPACING,
|
||||
padding: POPUP_GRID_SPACING,
|
||||
@ -140,8 +138,6 @@ AltTabPopup.prototype = {
|
||||
},
|
||||
|
||||
show : function(initialSelection) {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
global.window_group.add_actor(this._overlay);
|
||||
this._overlay.raise_top();
|
||||
this._overlay.show();
|
||||
@ -234,8 +230,6 @@ AltTabPopup.prototype = {
|
||||
},
|
||||
|
||||
_adjust_overlay : function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
if (this._selected && this._selected.icon_rect) {
|
||||
// We want to highlight a specific rectangle within the
|
||||
// task bar, so rearrange the pieces of the overlay to
|
||||
|
@ -26,6 +26,27 @@ const WELL_DEFAULT_COLUMNS = 4;
|
||||
const WELL_ITEM_HSPACING = 0;
|
||||
const WELL_ITEM_VSPACING = 4;
|
||||
|
||||
const WELL_MENU_POPUP_TIMEOUT_MS = 600;
|
||||
|
||||
const TRANSPARENT_COLOR = new Clutter.Color();
|
||||
TRANSPARENT_COLOR.from_pixel(0x00000000);
|
||||
|
||||
const WELL_MENU_BACKGROUND_COLOR = new Clutter.Color();
|
||||
WELL_MENU_BACKGROUND_COLOR.from_pixel(0x292929ff);
|
||||
const WELL_MENU_FONT = 'Sans 14px';
|
||||
const WELL_MENU_COLOR = new Clutter.Color();
|
||||
WELL_MENU_COLOR.from_pixel(0xffffffff);
|
||||
const WELL_MENU_SELECTED_COLOR = new Clutter.Color();
|
||||
WELL_MENU_SELECTED_COLOR.from_pixel(0x005b97ff);
|
||||
const WELL_MENU_BORDER_COLOR = new Clutter.Color();
|
||||
WELL_MENU_BORDER_COLOR.from_pixel(0x787878ff);
|
||||
const WELL_MENU_SEPARATOR_COLOR = new Clutter.Color();
|
||||
WELL_MENU_SEPARATOR_COLOR.from_pixel(0x787878ff);
|
||||
const WELL_MENU_BORDER_WIDTH = 1;
|
||||
const WELL_MENU_ARROW_SIZE = 12;
|
||||
const WELL_MENU_CORNER_RADIUS = 4;
|
||||
const WELL_MENU_PADDING = 4;
|
||||
|
||||
const MENU_ICON_SIZE = 24;
|
||||
const MENU_SPACING = 15;
|
||||
|
||||
@ -57,7 +78,13 @@ AppDisplayItem.prototype = {
|
||||
|
||||
// Opens an application represented by this display item.
|
||||
launch : function() {
|
||||
this._appInfo.launch();
|
||||
let windows = Shell.AppMonitor.get_default().get_windows_for_app(this._appInfo.get_id());
|
||||
if (windows.length > 0) {
|
||||
let mostRecentWindow = windows[0];
|
||||
Main.overview.activateWindow(mostRecentWindow, Clutter.get_current_event_time());
|
||||
} else {
|
||||
this._appInfo.launch();
|
||||
}
|
||||
},
|
||||
|
||||
//// Protected method overrides ////
|
||||
@ -161,21 +188,25 @@ MenuItem.prototype = {
|
||||
}
|
||||
Signals.addSignalMethods(MenuItem.prototype);
|
||||
|
||||
|
||||
/* This class represents a display containing a collection of application items.
|
||||
* The applications are sorted based on their popularity by default, and based on
|
||||
* their name if some search filter is applied.
|
||||
*
|
||||
* showPrefs - a boolean indicating if this AppDisplay should contain preference
|
||||
* applets, rather than applications
|
||||
*/
|
||||
function AppDisplay() {
|
||||
this._init();
|
||||
function AppDisplay(showPrefs) {
|
||||
this._init(showPrefs);
|
||||
}
|
||||
|
||||
AppDisplay.prototype = {
|
||||
__proto__: GenericDisplay.GenericDisplay.prototype,
|
||||
|
||||
_init : function() {
|
||||
_init : function(showPrefs) {
|
||||
GenericDisplay.GenericDisplay.prototype._init.call(this);
|
||||
|
||||
this._showPrefs = showPrefs;
|
||||
|
||||
this._menus = [];
|
||||
this._menuDisplays = [];
|
||||
|
||||
@ -327,36 +358,37 @@ AppDisplay.prototype = {
|
||||
|
||||
// Gets information about all applications by calling Gio.app_info_get_all().
|
||||
_refreshCache : function() {
|
||||
let me = this;
|
||||
if (!this._appsStale)
|
||||
return;
|
||||
this._allItems = {};
|
||||
this._appCategories = {};
|
||||
|
||||
// Loop over the toplevel menu items, load the set of desktop file ids
|
||||
// associated with each one, skipping empty menus
|
||||
let allMenus = this._appSystem.get_menus();
|
||||
this._menus = [];
|
||||
for (let i = 0; i < allMenus.length; i++) {
|
||||
let menu = allMenus[i];
|
||||
let menuApps = this._appSystem.get_applications_for_menu(menu.id);
|
||||
let hasVisibleApps = menuApps.some(function (app) { return !app.get_is_nodisplay(); });
|
||||
if (!hasVisibleApps) {
|
||||
continue;
|
||||
}
|
||||
this._menus.push(menu);
|
||||
for (let j = 0; j < menuApps.length; j++) {
|
||||
let app = menuApps[j];
|
||||
if (this._showPrefs) {
|
||||
// Get the desktop file ids for settings/preferences.
|
||||
// These are used for search results, but not in the app menus.
|
||||
let settings = this._appSystem.get_all_settings();
|
||||
for (let i = 0; i < settings.length; i++) {
|
||||
let app = settings[i];
|
||||
this._addApp(app);
|
||||
}
|
||||
}
|
||||
|
||||
// Now grab the desktop file ids for settings/preferences.
|
||||
// These show up in search, but not with the rest of apps.
|
||||
let settings = this._appSystem.get_all_settings();
|
||||
for (let i = 0; i < settings.length; i++) {
|
||||
let app = settings[i];
|
||||
this._addApp(app);
|
||||
} else {
|
||||
// Loop over the toplevel menu items, load the set of desktop file ids
|
||||
// associated with each one, skipping empty menus
|
||||
let allMenus = this._appSystem.get_menus();
|
||||
this._menus = [];
|
||||
for (let i = 0; i < allMenus.length; i++) {
|
||||
let menu = allMenus[i];
|
||||
let menuApps = this._appSystem.get_applications_for_menu(menu.id);
|
||||
let hasVisibleApps = menuApps.some(function (app) { return !app.get_is_nodisplay(); });
|
||||
if (!hasVisibleApps) {
|
||||
continue;
|
||||
}
|
||||
this._menus.push(menu);
|
||||
for (let j = 0; j < menuApps.length; j++) {
|
||||
let app = menuApps[j];
|
||||
this._addApp(app);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._appsStale = false;
|
||||
@ -448,35 +480,286 @@ AppDisplay.prototype = {
|
||||
|
||||
Signals.addSignalMethods(AppDisplay.prototype);
|
||||
|
||||
function WellDisplayItem(appInfo, isFavorite) {
|
||||
function WellMenu(source) {
|
||||
this._init(source);
|
||||
}
|
||||
|
||||
WellMenu.prototype = {
|
||||
_init: function(source) {
|
||||
this._source = source;
|
||||
|
||||
// Whether or not we successfully picked a window
|
||||
this.didActivateWindow = false;
|
||||
|
||||
this.actor = new Shell.GenericContainer({ reactive: true });
|
||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
||||
|
||||
this._windowContainer = new Shell.Menu({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
border_color: WELL_MENU_BORDER_COLOR,
|
||||
border: WELL_MENU_BORDER_WIDTH,
|
||||
background_color: WELL_MENU_BACKGROUND_COLOR,
|
||||
padding: 4,
|
||||
corner_radius: WELL_MENU_CORNER_RADIUS,
|
||||
width: Main.overview._dash.actor.width * 0.75 });
|
||||
this._windowContainer.connect('unselected', Lang.bind(this, this._onWindowUnselected));
|
||||
this._windowContainer.connect('selected', Lang.bind(this, this._onWindowSelected));
|
||||
this._windowContainer.connect('cancelled', Lang.bind(this, this._onWindowSelectionCancelled));
|
||||
this._windowContainer.connect('activate', Lang.bind(this, this._onWindowActivate));
|
||||
this.actor.add_actor(this._windowContainer);
|
||||
|
||||
// Stay popped up on release over application icon
|
||||
this._windowContainer.set_persistent_source(this._source.actor);
|
||||
|
||||
// Intercept events while the menu has the pointer grab to do window-related effects
|
||||
this._windowContainer.connect('enter-event', Lang.bind(this, this._onMenuEnter));
|
||||
this._windowContainer.connect('leave-event', Lang.bind(this, this._onMenuLeave));
|
||||
this._windowContainer.connect('button-release-event', Lang.bind(this, this._onMenuButtonRelease));
|
||||
|
||||
this._arrow = new Shell.DrawingArea();
|
||||
this._arrow.connect('redraw', Lang.bind(this, function (area, texture) {
|
||||
Shell.draw_box_pointer(texture, WELL_MENU_BORDER_COLOR, WELL_MENU_BACKGROUND_COLOR);
|
||||
}));
|
||||
this.actor.add_actor(this._arrow);
|
||||
|
||||
// Chain our visibility and lifecycle to that of the source
|
||||
source.actor.connect('notify::mapped', Lang.bind(this, function () {
|
||||
if (!source.actor.mapped)
|
||||
this._windowContainer.popdown();
|
||||
}));
|
||||
source.actor.connect('destroy', Lang.bind(this, function () { this.actor.destroy(); }));
|
||||
|
||||
global.stage.add_actor(this.actor);
|
||||
},
|
||||
|
||||
_getPreferredWidth: function(actor, forHeight, alloc) {
|
||||
let [min, natural] = this._windowContainer.get_preferred_width(forHeight);
|
||||
alloc.min_size = min + WELL_MENU_ARROW_SIZE;
|
||||
alloc.natural_size = natural + WELL_MENU_ARROW_SIZE;
|
||||
},
|
||||
|
||||
_getPreferredHeight: function(actor, forWidth, alloc) {
|
||||
let [min, natural] = this._windowContainer.get_preferred_height(forWidth);
|
||||
alloc.min_size = min;
|
||||
alloc.natural_size = natural;
|
||||
},
|
||||
|
||||
_allocate: function(actor, box, flags) {
|
||||
let childBox = new Clutter.ActorBox();
|
||||
|
||||
let width = box.x2 - box.x1;
|
||||
let height = box.y2 - box.y1;
|
||||
|
||||
childBox.x1 = 0;
|
||||
childBox.x2 = WELL_MENU_ARROW_SIZE;
|
||||
childBox.y1 = Math.floor((height / 2) - (WELL_MENU_ARROW_SIZE / 2));
|
||||
childBox.y2 = childBox.y1 + WELL_MENU_ARROW_SIZE;
|
||||
this._arrow.allocate(childBox, flags);
|
||||
|
||||
/* overlap by one pixel to hide the border */
|
||||
childBox.x1 = WELL_MENU_ARROW_SIZE - 1;
|
||||
childBox.x2 = width;
|
||||
childBox.y1 = 0;
|
||||
childBox.y2 = height;
|
||||
this._windowContainer.allocate(childBox, flags);
|
||||
},
|
||||
|
||||
_redisplay: function() {
|
||||
this._windowContainer.remove_all();
|
||||
|
||||
this.didActivateWindow = false;
|
||||
|
||||
let windows = this._source.windows;
|
||||
|
||||
this._windowContainer.show();
|
||||
|
||||
let iconsDiffer = false;
|
||||
let texCache = Shell.TextureCache.get_default();
|
||||
let firstIcon = windows[0].mini_icon;
|
||||
for (let i = 1; i < windows.length; i++) {
|
||||
if (!texCache.pixbuf_equal(windows[i].mini_icon, firstIcon)) {
|
||||
iconsDiffer = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let activeWorkspace = global.screen.get_active_workspace();
|
||||
|
||||
let currentWorkspaceWindows = windows.filter(function (w) {
|
||||
return w.get_workspace() == activeWorkspace;
|
||||
});
|
||||
let otherWorkspaceWindows = windows.filter(function (w) {
|
||||
return w.get_workspace() != activeWorkspace;
|
||||
});
|
||||
|
||||
this._appendWindows(currentWorkspaceWindows, iconsDiffer);
|
||||
if (currentWorkspaceWindows.length > 0 && otherWorkspaceWindows.length > 0) {
|
||||
let box = new Big.Box({ padding_top: 2, padding_bottom: 2 });
|
||||
box.append(new Clutter.Rectangle({ height: 1,
|
||||
color: WELL_MENU_SEPARATOR_COLOR }),
|
||||
Big.BoxPackFlags.EXPAND);
|
||||
this._windowContainer.append_separator(box, Big.BoxPackFlags.NONE);
|
||||
}
|
||||
this._appendWindows(otherWorkspaceWindows, iconsDiffer);
|
||||
},
|
||||
|
||||
_appendWindows: function (windows, iconsDiffer) {
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
let metaWindow = windows[i];
|
||||
|
||||
/* Use padding here rather than spacing in the box above so that
|
||||
* we have a larger reactive area.
|
||||
*/
|
||||
let box = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
padding_top: 4,
|
||||
padding_bottom: 4,
|
||||
spacing: 4,
|
||||
reactive: true });
|
||||
box._window = metaWindow;
|
||||
let vCenter;
|
||||
if (iconsDiffer) {
|
||||
vCenter = new Big.Box({ y_align: Big.BoxAlignment.CENTER });
|
||||
let icon = Shell.TextureCache.get_default().bind_pixbuf_property(metaWindow, "mini-icon");
|
||||
vCenter.append(icon, Big.BoxPackFlags.NONE);
|
||||
box.append(vCenter, Big.BoxPackFlags.NONE);
|
||||
}
|
||||
vCenter = new Big.Box({ y_align: Big.BoxAlignment.CENTER });
|
||||
let label = new Clutter.Text({ text: metaWindow.title,
|
||||
font_name: WELL_MENU_FONT,
|
||||
ellipsize: Pango.EllipsizeMode.END,
|
||||
color: WELL_MENU_COLOR });
|
||||
vCenter.append(label, Big.BoxPackFlags.NONE);
|
||||
box.append(vCenter, Big.BoxPackFlags.NONE);
|
||||
this._windowContainer.append(box, Big.BoxPackFlags.NONE);
|
||||
}
|
||||
},
|
||||
|
||||
popup: function() {
|
||||
let [stageX, stageY] = this._source.actor.get_transformed_position();
|
||||
let [stageWidth, stageHeight] = this._source.actor.get_transformed_size();
|
||||
|
||||
this._redisplay();
|
||||
|
||||
this._windowContainer.popup(0, Clutter.get_current_event_time());
|
||||
|
||||
this.emit('popup', true);
|
||||
|
||||
let x = Math.floor(stageX + stageWidth);
|
||||
let y = Math.floor(stageY + (stageHeight / 2) - (this.actor.height / 2));
|
||||
this.actor.set_position(x, y);
|
||||
this.actor.show();
|
||||
},
|
||||
|
||||
_findWindowCloneForActor: function (actor) {
|
||||
if (actor._delegate instanceof Workspaces.WindowClone)
|
||||
return actor._delegate;
|
||||
return null;
|
||||
},
|
||||
|
||||
// This function is called while the menu has a pointer grab; what we want
|
||||
// to do is see if the mouse was released over a window clone actor
|
||||
_onMenuButtonRelease: function (actor, event) {
|
||||
let clone = this._findWindowCloneForActor(event.get_source());
|
||||
if (clone) {
|
||||
this.didActivateWindow = true;
|
||||
Main.overview.activateWindow(clone.metaWindow, event.get_time());
|
||||
}
|
||||
},
|
||||
|
||||
_setHighlightWindow: function (metaWindow) {
|
||||
let children = this._windowContainer.get_children();
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
let child = children[i];
|
||||
let menuMetaWindow = child._window;
|
||||
if (metaWindow != null && menuMetaWindow == metaWindow) {
|
||||
child.background_color = WELL_MENU_SELECTED_COLOR;
|
||||
} else {
|
||||
child.background_color = TRANSPARENT_COLOR;
|
||||
}
|
||||
}
|
||||
this.emit('highlight-window', metaWindow);
|
||||
},
|
||||
|
||||
// Called while menu has a pointer grab
|
||||
_onMenuEnter: function (actor, event) {
|
||||
let clone = this._findWindowCloneForActor(event.get_source());
|
||||
if (clone) {
|
||||
this._setHighlightWindow(clone.metaWindow);
|
||||
}
|
||||
},
|
||||
|
||||
// Called while menu has a pointer grab
|
||||
_onMenuLeave: function (actor, event) {
|
||||
let clone = this._findWindowCloneForActor(event.get_source());
|
||||
if (clone) {
|
||||
this._setHighlightWindow(null);
|
||||
}
|
||||
},
|
||||
|
||||
_onWindowUnselected: function (actor, child) {
|
||||
this._setHighlightWindow(null);
|
||||
},
|
||||
|
||||
_onWindowSelected: function (actor, child) {
|
||||
this._setHighlightWindow(child._window);
|
||||
},
|
||||
|
||||
_onWindowActivate: function (actor, child) {
|
||||
let metaWindow = child._window;
|
||||
this.didActivateWindow = true;
|
||||
Main.overview.activateWindow(metaWindow, Clutter.get_current_event_time());
|
||||
this.emit('popup', false);
|
||||
this.actor.hide();
|
||||
},
|
||||
|
||||
_onWindowSelectionCancelled: function () {
|
||||
this.emit('highlight-window', null);
|
||||
this.emit('popup', false);
|
||||
this.actor.hide();
|
||||
}
|
||||
}
|
||||
|
||||
Signals.addSignalMethods(WellMenu.prototype);
|
||||
|
||||
function BaseWellItem(appInfo, isFavorite) {
|
||||
this._init(appInfo, isFavorite);
|
||||
}
|
||||
|
||||
WellDisplayItem.prototype = {
|
||||
__proto__ : AppIcon.AppIcon.prototype,
|
||||
|
||||
_init : function(appInfo, isFavorite) {
|
||||
AppIcon.AppIcon.prototype._init.call(this, appInfo);
|
||||
|
||||
BaseWellItem.prototype = {
|
||||
_init: function(appInfo, isFavorite) {
|
||||
this.appInfo = appInfo;
|
||||
this.isFavorite = isFavorite;
|
||||
this.icon = new AppIcon.AppIcon(appInfo);
|
||||
this.windows = this.icon.windows;
|
||||
this.actor = new Shell.ButtonBox({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
border: WELL_MENU_BORDER_WIDTH,
|
||||
corner_radius: WELL_MENU_CORNER_RADIUS,
|
||||
reactive: true });
|
||||
this.icon.actor._delegate = this;
|
||||
this._draggable = DND.makeDraggable(this.icon.actor, true);
|
||||
|
||||
this.actor.connect('button-release-event', Lang.bind(this, function (b, e) {
|
||||
this._handleActivate();
|
||||
// Do these as anonymous functions to avoid conflict with handlers in subclasses
|
||||
this.actor.connect('button-press-event', Lang.bind(this, function(actor, event) {
|
||||
let [stageX, stageY] = event.get_coords();
|
||||
this._dragStartX = stageX;
|
||||
this._dragStartY = stageY;
|
||||
return false;
|
||||
}));
|
||||
|
||||
let draggable = DND.makeDraggable(this.actor);
|
||||
},
|
||||
|
||||
_handleActivate: function () {
|
||||
if (this._windows.length == 0) {
|
||||
this.appInfo.launch();
|
||||
Main.overview.hide();
|
||||
} else {
|
||||
/* Pick the first window and activate it;
|
||||
* In the future, we want to have a menu dropdown here. */
|
||||
let first = this._windows[0];
|
||||
Main.overview.activateWindow(first, Clutter.get_current_event_time());
|
||||
}
|
||||
this.actor.connect('notify::hover', Lang.bind(this, function () {
|
||||
let hover = this.actor.hover;
|
||||
if (!hover) {
|
||||
if (this.actor.pressed && this._dragStartX != null) {
|
||||
this.actor.fake_release();
|
||||
this._draggable.startDrag(this.icon.actor, this._dragStartX, this._dragStartY,
|
||||
Clutter.get_current_event_time());
|
||||
} else {
|
||||
this._dragStartX = null;
|
||||
this._dragStartY = null;
|
||||
}
|
||||
}
|
||||
}));
|
||||
this.actor.append(this.icon.actor, Big.BoxPackFlags.NONE);
|
||||
},
|
||||
|
||||
shellWorkspaceLaunch : function() {
|
||||
@ -492,17 +775,140 @@ WellDisplayItem.prototype = {
|
||||
},
|
||||
|
||||
getDragActor: function(stageX, stageY) {
|
||||
return this.appInfo.create_icon_texture(this._icon.height);
|
||||
return this.icon.getDragActor(stageX, stageY);
|
||||
},
|
||||
|
||||
// Returns the original icon that is being used as a source for the cloned texture
|
||||
// that represents the item as it is being dragged.
|
||||
getDragActorSource: function() {
|
||||
return this._icon;
|
||||
return this.icon.getDragActorSource();
|
||||
}
|
||||
}
|
||||
|
||||
function RunningWellItem(appInfo, isFavorite) {
|
||||
this._init(appInfo, isFavorite);
|
||||
}
|
||||
|
||||
RunningWellItem.prototype = {
|
||||
__proto__: BaseWellItem.prototype,
|
||||
|
||||
_init: function(appInfo, isFavorite) {
|
||||
BaseWellItem.prototype._init.call(this, appInfo, isFavorite);
|
||||
|
||||
this._menuTimeoutId = 0;
|
||||
this._menu = null;
|
||||
this._dragStartX = 0;
|
||||
this._dragStartY = 0;
|
||||
|
||||
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
|
||||
this.actor.connect('notify::hover', Lang.bind(this, this._onHoverChanged));
|
||||
this.actor.connect('activate', Lang.bind(this, this._onActivate));
|
||||
},
|
||||
|
||||
setWidth: function(width) {
|
||||
this._nameBox.width = width + GLOW_PADDING * 2;
|
||||
_onActivate: function (actor, event) {
|
||||
let modifiers = event.get_state();
|
||||
|
||||
if (this._menuTimeoutId > 0) {
|
||||
Mainloop.source_remove(this._menuTimeoutId);
|
||||
this._menuTimeoutId = 0;
|
||||
}
|
||||
|
||||
if (modifiers & Clutter.ModifierType.CONTROL_MASK) {
|
||||
this.appInfo.launch();
|
||||
} else {
|
||||
this.activateMostRecentWindow();
|
||||
}
|
||||
},
|
||||
|
||||
activateMostRecentWindow: function () {
|
||||
// The _get_windows_for_app sorts them for us
|
||||
let mostRecentWindow = this.windows[0];
|
||||
Main.overview.activateWindow(mostRecentWindow, Clutter.get_current_event_time());
|
||||
},
|
||||
|
||||
_onHoverChanged: function() {
|
||||
let hover = this.actor.hover;
|
||||
if (!hover && this._menuTimeoutId > 0) {
|
||||
Mainloop.source_remove(this._menuTimeoutId);
|
||||
this._menuTimeoutId = 0;
|
||||
}
|
||||
},
|
||||
|
||||
_onButtonPress: function(actor, event) {
|
||||
if (this._menuTimeoutId > 0)
|
||||
Mainloop.source_remove(this._menuTimeoutId);
|
||||
this._menuTimeoutId = Mainloop.timeout_add(WELL_MENU_POPUP_TIMEOUT_MS,
|
||||
Lang.bind(this, this._popupMenu));
|
||||
return false;
|
||||
},
|
||||
|
||||
_popupMenu: function() {
|
||||
this._menuTimeoutId = 0;
|
||||
|
||||
this.actor.fake_release();
|
||||
|
||||
if (this._menu == null) {
|
||||
this._menu = new WellMenu(this);
|
||||
this._menu.connect('highlight-window', Lang.bind(this, function (menu, metaWindow) {
|
||||
Main.overview.getWorkspacesForWindow(metaWindow).setHighlightWindow(metaWindow);
|
||||
}));
|
||||
this._menu.connect('popup', Lang.bind(this, function (menu, isPoppedUp) {
|
||||
let id;
|
||||
|
||||
// If we successfully picked a window, don't reset the workspace
|
||||
// state, since picking a window already did that.
|
||||
if (!isPoppedUp && menu.didActivateWindow)
|
||||
return;
|
||||
if (isPoppedUp)
|
||||
id = this.appInfo.get_id();
|
||||
else
|
||||
id = null;
|
||||
|
||||
Main.overview.getWorkspacesForWindow(null).setApplicationWindowSelection(id);
|
||||
}));
|
||||
}
|
||||
|
||||
this._menu.popup();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function InactiveWellItem(appInfo, isFavorite) {
|
||||
this._init(appInfo, isFavorite);
|
||||
}
|
||||
|
||||
InactiveWellItem.prototype = {
|
||||
__proto__: BaseWellItem.prototype,
|
||||
|
||||
_init : function(appInfo, isFavorite) {
|
||||
BaseWellItem.prototype._init.call(this, appInfo, isFavorite);
|
||||
|
||||
this.actor.connect('notify::pressed', Lang.bind(this, this._onPressedChanged));
|
||||
this.actor.connect('notify::hover', Lang.bind(this, this._onHoverChanged));
|
||||
this.actor.connect('activate', Lang.bind(this, this._onActivate));
|
||||
},
|
||||
|
||||
_onPressedChanged: function() {
|
||||
let pressed = this.actor.pressed;
|
||||
if (pressed) {
|
||||
this.actor.border_color = WELL_MENU_BORDER_COLOR;
|
||||
} else {
|
||||
this.actor.border_color = TRANSPARENT_COLOR;
|
||||
}
|
||||
},
|
||||
|
||||
_onHoverChanged: function() {
|
||||
let hover = this.actor.hover;
|
||||
},
|
||||
|
||||
_onActivate: function() {
|
||||
if (this.windows.length == 0) {
|
||||
this.appInfo.launch();
|
||||
Main.overview.hide();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
@ -755,22 +1161,25 @@ AppWell.prototype = {
|
||||
this._displays = displays;
|
||||
},
|
||||
|
||||
_addApps: function(apps) {
|
||||
_addApps: function(apps, isFavorite) {
|
||||
for (let i = 0; i < apps.length; i++) {
|
||||
let app = apps[i];
|
||||
let display = new WellDisplayItem(app, this.isFavorite);
|
||||
let windows = this._appMonitor.get_windows_for_app(app.get_id());
|
||||
let display;
|
||||
if (windows.length > 0)
|
||||
display = new RunningWellItem(app, isFavorite);
|
||||
else
|
||||
display = new InactiveWellItem(app, isFavorite);
|
||||
this._grid.actor.add_actor(display.actor);
|
||||
}
|
||||
},
|
||||
|
||||
// Draggable target interface
|
||||
acceptDrop : function(source, actor, x, y, time) {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
let appSystem = Shell.AppSystem.get_default();
|
||||
|
||||
let app = null;
|
||||
if (source instanceof WellDisplayItem) {
|
||||
if (source instanceof BaseWellItem) {
|
||||
app = source.appInfo;
|
||||
} else if (source instanceof AppDisplayItem) {
|
||||
app = appSystem.lookup_cached_app(source.getId());
|
||||
|
@ -24,20 +24,22 @@ function AppIcon(appInfo) {
|
||||
AppIcon.prototype = {
|
||||
_init : function(appInfo) {
|
||||
this.appInfo = appInfo;
|
||||
this.windows = Shell.AppMonitor.get_default().get_windows_for_app(appInfo.get_id());
|
||||
for (let i = 0; i < this.windows.length; i++) {
|
||||
this.windows[i].connect('notify::user-time', Lang.bind(this, this._resortWindows));
|
||||
}
|
||||
this._resortWindows();
|
||||
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
corner_radius: 2,
|
||||
border: 0,
|
||||
padding: 1,
|
||||
border_color: GenericDisplay.ITEM_DISPLAY_SELECTED_BACKGROUND_COLOR,
|
||||
reactive: true });
|
||||
this.actor._delegate = this;
|
||||
|
||||
let iconBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
x_align: Big.BoxAlignment.CENTER,
|
||||
y_align: Big.BoxAlignment.CENTER });
|
||||
this._icon = appInfo.create_icon_texture(APP_ICON_SIZE);
|
||||
iconBox.append(this._icon, Big.BoxPackFlags.NONE);
|
||||
this.icon = appInfo.create_icon_texture(APP_ICON_SIZE);
|
||||
iconBox.append(this.icon, Big.BoxPackFlags.NONE);
|
||||
|
||||
this.actor.append(iconBox, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
@ -56,7 +58,7 @@ AppIcon.prototype = {
|
||||
text: appInfo.get_name() });
|
||||
nameBox.add_actor(this._name);
|
||||
this._glowBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL });
|
||||
let glowPath = GLib.filename_to_uri(Shell.Global.get().imagedir + 'app-well-glow.png', '');
|
||||
let glowPath = GLib.filename_to_uri(global.imagedir + 'app-well-glow.png', '');
|
||||
for (let i = 0; i < this._windows.length && i < 3; i++) {
|
||||
let glow = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER,
|
||||
glowPath, -1, -1);
|
||||
@ -98,7 +100,6 @@ AppIcon.prototype = {
|
||||
this._name.allocate(childBox, flags);
|
||||
|
||||
// Now the glow
|
||||
|
||||
if (this._glowBox != null) {
|
||||
let glowPaddingHoriz = Math.max(0, xPadding - GLOW_PADDING_HORIZONTAL);
|
||||
glowPaddingHoriz = Math.max(GLOW_PADDING_HORIZONTAL, glowPaddingHoriz);
|
||||
@ -108,5 +109,25 @@ AppIcon.prototype = {
|
||||
childBox.y2 = availHeight;
|
||||
this._glowBox.allocate(childBox, flags);
|
||||
}
|
||||
},
|
||||
|
||||
_resortWindows: function() {
|
||||
this.windows.sort(function (a, b) {
|
||||
let timeA = a.get_user_time();
|
||||
let timeB = b.get_user_time();
|
||||
if (timeA == timeB)
|
||||
return 0;
|
||||
else if (timeA > timeB)
|
||||
return -1;
|
||||
return 1;
|
||||
});
|
||||
},
|
||||
|
||||
getDragActor: function() {
|
||||
return this.appInfo.create_icon_texture(APP_ICON_SIZE);
|
||||
},
|
||||
|
||||
getDragActorSource: function() {
|
||||
return this.icon;
|
||||
}
|
||||
};
|
||||
|
@ -28,8 +28,6 @@ function Button(widget, buttonColor, pressedButtonColor, textColor, font) {
|
||||
|
||||
Button.prototype = {
|
||||
_init : function(widgetOrText, buttonColor, pressedButtonColor, textColor, font) {
|
||||
let me = this;
|
||||
|
||||
this._buttonColor = buttonColor
|
||||
if (buttonColor == null)
|
||||
this._buttonColor = DEFAULT_BUTTON_COLOR;
|
||||
@ -108,16 +106,15 @@ iconButton.prototype = {
|
||||
this.actor.set_opacity(0);
|
||||
parent.connect("enter-event", Lang.bind(this, function(actor, event) {
|
||||
this._shouldHide = false;
|
||||
|
||||
// Nothing to do if the cursor has come back from a child of the parent actor
|
||||
if (actor.get_children().indexOf(Shell.get_event_related(event)) != -1)
|
||||
if (actor.get_children().indexOf(event.get_related()) != -1)
|
||||
return;
|
||||
|
||||
this._fadeIn();
|
||||
}));
|
||||
parent.connect("leave-event", Lang.bind(this, function(actor, event) {
|
||||
// Nothing to do if the cursor has merely entered a child of the parent actor
|
||||
if (actor.get_children().indexOf(Shell.get_event_related(event)) != -1)
|
||||
if (actor.get_children().indexOf(event.get_related()) != -1)
|
||||
return;
|
||||
|
||||
// Remember that we should not be visible to hide the button if forceShow is unset
|
||||
|
@ -18,8 +18,6 @@ function Chrome() {
|
||||
|
||||
Chrome.prototype = {
|
||||
_init: function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
// The group itself has zero size so it doesn't interfere with DND
|
||||
this.actor = new Clutter.Group({ width: 0, height: 0 });
|
||||
global.stage.add_actor(this.actor);
|
||||
@ -238,7 +236,6 @@ Chrome.prototype = {
|
||||
},
|
||||
|
||||
_windowsRestacked: function() {
|
||||
let global = Shell.Global.get();
|
||||
let windows = global.get_windows();
|
||||
|
||||
// The chrome layer should be visible unless there is a window
|
||||
@ -280,7 +277,6 @@ Chrome.prototype = {
|
||||
},
|
||||
|
||||
_updateRegions: function() {
|
||||
let global = Shell.Global.get();
|
||||
let rects = [], struts = [], i;
|
||||
|
||||
delete this._updateRegionIdle;
|
||||
|
356
js/ui/dash.js
356
js/ui/dash.js
@ -70,6 +70,34 @@ const PANE_BORDER_WIDTH = 2;
|
||||
const PANE_BACKGROUND_COLOR = new Clutter.Color();
|
||||
PANE_BACKGROUND_COLOR.from_pixel(0x000000f4);
|
||||
|
||||
const APPS = "apps";
|
||||
const PREFS = "prefs";
|
||||
const DOCS = "docs";
|
||||
|
||||
/*
|
||||
* Returns the index in an array of a given length that is obtained
|
||||
* if the provided index is incremented by an increment and the array
|
||||
* is wrapped in if necessary.
|
||||
*
|
||||
* index: prior index, expects 0 <= index < length
|
||||
* increment: the change in index, expects abs(increment) <= length
|
||||
* length: the length of the array
|
||||
*/
|
||||
function _getIndexWrapped(index, increment, length) {
|
||||
return (index + increment + length) % length;
|
||||
}
|
||||
|
||||
function _createDisplay(displayType) {
|
||||
if (displayType == APPS)
|
||||
return new AppDisplay.AppDisplay();
|
||||
else if (displayType == PREFS)
|
||||
return new AppDisplay.AppDisplay(true);
|
||||
else if (displayType == DOCS)
|
||||
return new DocDisplay.DocDisplay();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function Pane() {
|
||||
this._init();
|
||||
}
|
||||
@ -92,7 +120,6 @@ Pane.prototype = {
|
||||
let chromeTop = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
spacing: 6 });
|
||||
|
||||
let global = Shell.Global.get();
|
||||
let closeIconUri = "file://" + global.imagedir + "close.svg";
|
||||
let closeIcon = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER,
|
||||
closeIconUri,
|
||||
@ -146,12 +173,12 @@ Pane.prototype = {
|
||||
}
|
||||
Signals.addSignalMethods(Pane.prototype);
|
||||
|
||||
function ResultArea(displayClass, enableNavigation) {
|
||||
this._init(displayClass, enableNavigation);
|
||||
function ResultArea(displayType, enableNavigation) {
|
||||
this._init(displayType, enableNavigation);
|
||||
}
|
||||
|
||||
ResultArea.prototype = {
|
||||
_init : function(displayClass, enableNavigation) {
|
||||
_init : function(displayType, enableNavigation) {
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL });
|
||||
this.resultsContainer = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
spacing: DEFAULT_PADDING
|
||||
@ -160,7 +187,7 @@ ResultArea.prototype = {
|
||||
this.navContainer = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL });
|
||||
this.resultsContainer.append(this.navContainer, Big.BoxPackFlags.NONE);
|
||||
|
||||
this.display = new displayClass();
|
||||
this.display = _createDisplay(displayType);
|
||||
|
||||
this.navArea = this.display.getNavigationArea();
|
||||
if (enableNavigation && this.navArea)
|
||||
@ -217,10 +244,10 @@ ResultPane.prototype = {
|
||||
this._dash = dash;
|
||||
},
|
||||
|
||||
// Create an instance of displayClass and pack it into this pane's
|
||||
// content area. Return the displayClass instance.
|
||||
packResults: function(displayClass, enableNavigation) {
|
||||
let resultArea = new ResultArea(displayClass, enableNavigation);
|
||||
// Create a display of displayType and pack it into this pane's
|
||||
// content area. Return the display.
|
||||
packResults: function(displayType, enableNavigation) {
|
||||
let resultArea = new ResultArea(displayType, enableNavigation);
|
||||
|
||||
createPaneForDetails(this._dash, resultArea.display);
|
||||
|
||||
@ -288,7 +315,6 @@ SearchEntry.prototype = {
|
||||
padding_right: 4 });
|
||||
box.append(this._iconBox, Big.BoxPackFlags.END);
|
||||
|
||||
let global = Shell.Global.get();
|
||||
let magnifierUri = "file://" + global.imagedir + "magnifier.svg";
|
||||
this._magnifierIcon = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER,
|
||||
magnifierUri, 18, 18);
|
||||
@ -408,7 +434,6 @@ BackLink.prototype = {
|
||||
border_right: SECTION_BORDER,
|
||||
border_color: SECTION_BORDER_COLOR });
|
||||
|
||||
let global = Shell.Global.get();
|
||||
let backIconUri = "file://" + global.imagedir + "back.svg";
|
||||
let backIcon = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER,
|
||||
backIconUri,
|
||||
@ -557,8 +582,6 @@ function Dash() {
|
||||
|
||||
Dash.prototype = {
|
||||
_init : function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
// dash and the popup panes need to be reactive so that the clicks in unoccupied places on them
|
||||
// are not passed to the transparent background underneath them. This background is used for the workspaces area when
|
||||
// the additional dash panes are being shown and it handles clicks by closing the additional panes, so that the user
|
||||
@ -612,45 +635,62 @@ Dash.prototype = {
|
||||
this._searchTimeoutId = 0;
|
||||
let text = this._searchEntry.getText();
|
||||
text = text.replace(/^\s+/g, "").replace(/\s+$/g, "");
|
||||
this._appSearchResultArea.display.setSearch(text);
|
||||
this._docSearchResultArea.display.setSearch(text);
|
||||
|
||||
let appsCount = this._appSearchResultArea.display.getMatchedItemsCount() + "";
|
||||
let docsCount = this._docSearchResultArea.display.getMatchedItemsCount() + "";
|
||||
|
||||
this._appSearchHeader.countText.text = appsCount;
|
||||
this._docSearchHeader.countText.text = docsCount;
|
||||
let selectionSet = false;
|
||||
|
||||
if (this._appSearchResultsOnlyShown)
|
||||
this._searchResultsSection.header.setCountText(appsCount);
|
||||
else if (this._docSearchResultsOnlyShown)
|
||||
this._searchResultsSection.header.setCountText(docsCount);
|
||||
|
||||
if (this._appSearchResultArea.display.hasItems() && !this._docSearchResultsOnlyShown) {
|
||||
this._appSearchResultArea.display.selectFirstItem();
|
||||
this._docSearchResultArea.display.unsetSelected();
|
||||
} else if (this._docSearchResultArea.display.hasItems() && !this._appSearchResultsOnlyShown) {
|
||||
this._docSearchResultArea.display.selectFirstItem();
|
||||
this._appSearchResultArea.display.unsetSelected();
|
||||
for (var i = 0; i < this._searchSections.length; i++) {
|
||||
let section = this._searchSections[i];
|
||||
section.resultArea.display.setSearch(text);
|
||||
let itemCount = section.resultArea.display.getMatchedItemsCount();
|
||||
let itemCountText = itemCount + "";
|
||||
section.header.countText.text = itemCountText;
|
||||
|
||||
if (this._searchResultsSingleShownSection == section.type) {
|
||||
this._searchResultsSection.header.setCountText(itemCountText);
|
||||
if (itemCount == 0) {
|
||||
section.resultArea.actor.hide();
|
||||
} else {
|
||||
section.resultArea.actor.show();
|
||||
}
|
||||
} else if (this._searchResultsSingleShownSection == null) {
|
||||
// Don't show the section if it has no results
|
||||
if (itemCount == 0) {
|
||||
section.header.actor.hide();
|
||||
section.resultArea.actor.hide();
|
||||
} else {
|
||||
section.header.actor.show();
|
||||
section.resultArea.actor.show();
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh the selection when a new search is applied.
|
||||
section.resultArea.display.unsetSelected();
|
||||
if (!selectionSet && section.resultArea.display.hasItems() &&
|
||||
(this._searchResultsSingleShownSection == null || this._searchResultsSingleShownSection == section.type)) {
|
||||
section.resultArea.display.selectFirstItem();
|
||||
selectionSet = true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}));
|
||||
}));
|
||||
this._searchEntry.entry.connect('activate', Lang.bind(this, function (se) {
|
||||
// only one of the displays will have an item selected, so it's ok to
|
||||
// call activateSelected() on all of them
|
||||
this._appSearchResultArea.display.activateSelected();
|
||||
this._docSearchResultArea.display.activateSelected();
|
||||
// Only one of the displays will have an item selected, so it's ok to
|
||||
// call activateSelected() on all of them.
|
||||
for (var i = 0; i < this._searchSections.length; i++) {
|
||||
let section = this._searchSections[i];
|
||||
section.resultArea.display.activateSelected();
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
this._searchEntry.entry.connect('key-press-event', Lang.bind(this, function (se, e) {
|
||||
let text = this._searchEntry.getText();
|
||||
let symbol = Shell.get_event_key_symbol(e);
|
||||
let symbol = e.get_key_symbol();
|
||||
if (symbol == Clutter.Escape) {
|
||||
// Escape will keep clearing things back to the desktop.
|
||||
// If we are showing a particular section of search, go back to all sections.
|
||||
if (this._appSearchResultsOnlyShown || this._docSearchResultsOnlyShown)
|
||||
if (this._searchResultsSingleShownSection != null)
|
||||
this._showAllSearchSections();
|
||||
// If we have an active search, we remove it.
|
||||
else if (this._searchActive)
|
||||
@ -669,30 +709,38 @@ Dash.prototype = {
|
||||
// too, but there doesn't seem to be any flickering if we first select
|
||||
// something in one display, but then unset the selection, and move
|
||||
// it to the other display, so it's ok to do that.
|
||||
if (this._appSearchResultArea.display.hasSelected()) {
|
||||
if (!this._appSearchResultArea.display.selectUp() && this._docSearchResultArea.display.hasItems() && !this._appSearchResultsOnlyShown) {
|
||||
this._docSearchResultArea.display.selectLastItem();
|
||||
this._appSearchResultArea.display.unsetSelected();
|
||||
}
|
||||
} else if (this._docSearchResultArea.display.hasSelected()) {
|
||||
if (!this._docSearchResultArea.display.selectUp() && this._appSearchResultArea.display.hasItems() && !this._docSearchResultsOnlyShown) {
|
||||
this._appSearchResultArea.display.selectLastItem();
|
||||
this._docSearchResultArea.display.unsetSelected();
|
||||
for (var i = 0; i < this._searchSections.length; i++) {
|
||||
let section = this._searchSections[i];
|
||||
if (section.resultArea.display.hasSelected() && !section.resultArea.display.selectUp()) {
|
||||
if (this._searchResultsSingleShownSection != section.type) {
|
||||
// We need to move the selection to the next section above this section that has items,
|
||||
// wrapping around at the bottom, if necessary.
|
||||
let newSectionIndex = this._findAnotherSectionWithItems(i, -1);
|
||||
if (newSectionIndex >= 0) {
|
||||
this._searchSections[newSectionIndex].resultArea.display.selectLastItem();
|
||||
section.resultArea.display.unsetSelected();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if (symbol == Clutter.Down) {
|
||||
if (!this._searchActive)
|
||||
return true;
|
||||
if (this._appSearchResultArea.display.hasSelected()) {
|
||||
if (!this._appSearchResultArea.display.selectDown() && this._docSearchResultArea.display.hasItems() && !this._appSearchResultsOnlyShown) {
|
||||
this._docSearchResultArea.display.selectFirstItem();
|
||||
this._appSearchResultArea.display.unsetSelected();
|
||||
}
|
||||
} else if (this._docSearchResultArea.display.hasSelected()) {
|
||||
if (!this._docSearchResultArea.display.selectDown() && this._appSearchResultArea.display.hasItems() && !this._docSearchResultsOnlyShown) {
|
||||
this._appSearchResultArea.display.selectFirstItem();
|
||||
this._docSearchResultArea.display.unsetSelected();
|
||||
for (var i = 0; i < this._searchSections.length; i++) {
|
||||
let section = this._searchSections[i];
|
||||
if (section.resultArea.display.hasSelected() && !section.resultArea.display.selectDown()) {
|
||||
if (this._searchResultsSingleShownSection != section.type) {
|
||||
// We need to move the selection to the next section below this section that has items,
|
||||
// wrapping around at the top, if necessary.
|
||||
let newSectionIndex = this._findAnotherSectionWithItems(i, 1);
|
||||
if (newSectionIndex >= 0) {
|
||||
this._searchSections[newSectionIndex].resultArea.display.selectFirstItem();
|
||||
section.resultArea.display.unsetSelected();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -710,7 +758,7 @@ Dash.prototype = {
|
||||
this._appsSection.header.moreLink.connect('activated', Lang.bind(this, function (link) {
|
||||
if (this._moreAppsPane == null) {
|
||||
this._moreAppsPane = new ResultPane(this);
|
||||
this._moreAppsPane.packResults(AppDisplay.AppDisplay, true);
|
||||
this._moreAppsPane.packResults(APPS, true);
|
||||
this._addPane(this._moreAppsPane);
|
||||
link.setPane(this._moreAppsPane);
|
||||
}
|
||||
@ -738,7 +786,7 @@ Dash.prototype = {
|
||||
this._docsSection.header.moreLink.connect('activated', Lang.bind(this, function (link) {
|
||||
if (this._moreDocsPane == null) {
|
||||
this._moreDocsPane = new ResultPane(this);
|
||||
this._moreDocsPane.packResults(DocDisplay.DocDisplay, true);
|
||||
this._moreDocsPane.packResults(DOCS, true);
|
||||
this._addPane(this._moreDocsPane);
|
||||
link.setPane(this._moreDocsPane);
|
||||
}
|
||||
@ -750,43 +798,49 @@ Dash.prototype = {
|
||||
|
||||
this._searchResultsSection = new Section(_("SEARCH RESULTS"), true);
|
||||
|
||||
this._searchResultsSingleShownSection = null;
|
||||
|
||||
this._searchResultsSection.header.connect('back-link-activated', Lang.bind(this, function () {
|
||||
if (this._appSearchResultsOnlyShown)
|
||||
this._toggleOnlyAppSearchShown();
|
||||
else if (this._docSearchResultsOnlyShown)
|
||||
this._toggleOnlyDocSearchShown();
|
||||
this._showAllSearchSections();
|
||||
}));
|
||||
|
||||
this._appSearchResultsOnlyShown = false;
|
||||
this._appSearchHeader = new SearchSectionHeader(_("APPLICATIONS"),
|
||||
Lang.bind(this,
|
||||
function () {
|
||||
this._toggleOnlyAppSearchShown();
|
||||
}));
|
||||
this._searchResultsSection.content.append(this._appSearchHeader.actor, Big.BoxPackFlags.NONE);
|
||||
this._appSearchResultArea = new ResultArea(AppDisplay.AppDisplay, false);
|
||||
this._appSearchResultArea.controlBox.hide();
|
||||
this._searchResultsSection.content.append(this._appSearchResultArea.actor, Big.BoxPackFlags.EXPAND);
|
||||
createPaneForDetails(this, this._appSearchResultArea.display);
|
||||
this._searchSections = [
|
||||
{ type: APPS,
|
||||
title: _("APPLICATIONS"),
|
||||
header: null,
|
||||
resultArea: null
|
||||
},
|
||||
{ type: PREFS,
|
||||
title: _("PREFERENCES"),
|
||||
header: null,
|
||||
resultArea: null
|
||||
},
|
||||
{ type: DOCS,
|
||||
title: _("RECENT DOCUMENTS"),
|
||||
header: null,
|
||||
resultArea: null
|
||||
}
|
||||
];
|
||||
|
||||
this._docSearchResultsOnlyShown = false;
|
||||
this._docSearchHeader = new SearchSectionHeader(_("RECENT DOCUMENTS"),
|
||||
Lang.bind(this,
|
||||
function () {
|
||||
this._toggleOnlyDocSearchShown();
|
||||
}));
|
||||
this._searchResultsSection.content.append(this._docSearchHeader.actor, Big.BoxPackFlags.NONE);
|
||||
this._docSearchResultArea = new ResultArea(DocDisplay.DocDisplay, false);
|
||||
this._docSearchResultArea.controlBox.hide();
|
||||
this._searchResultsSection.content.append(this._docSearchResultArea.actor, Big.BoxPackFlags.EXPAND);
|
||||
createPaneForDetails(this, this._docSearchResultArea.display);
|
||||
for (var i = 0; i < this._searchSections.length; i++) {
|
||||
let section = this._searchSections[i];
|
||||
section.header = new SearchSectionHeader(section.title,
|
||||
Lang.bind(this,
|
||||
function () {
|
||||
this._showSingleSearchSection(section.type);
|
||||
}));
|
||||
this._searchResultsSection.content.append(section.header.actor, Big.BoxPackFlags.NONE);
|
||||
section.resultArea = new ResultArea(section.type, false);
|
||||
section.resultArea.controlBox.hide();
|
||||
this._searchResultsSection.content.append(section.resultArea.actor, Big.BoxPackFlags.EXPAND);
|
||||
createPaneForDetails(this, section.resultArea.display);
|
||||
}
|
||||
|
||||
this.sectionArea.append(this._searchResultsSection.actor, Big.BoxPackFlags.EXPAND);
|
||||
this._searchResultsSection.actor.hide();
|
||||
},
|
||||
|
||||
show: function() {
|
||||
let global = Shell.Global.get();
|
||||
global.stage.set_key_focus(this._searchEntry.entry);
|
||||
},
|
||||
|
||||
@ -831,77 +885,79 @@ Dash.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_toggleOnlyAppSearchShown: function() {
|
||||
if (this._appSearchResultsOnlyShown) {
|
||||
this._setDocSearchShown(true);
|
||||
} else {
|
||||
this._setDocSearchShown(false);
|
||||
_showSingleSearchSection: function(type) {
|
||||
// We currently don't allow going from showing one section to showing another section.
|
||||
if (this._searchResultsSingleShownSection != null) {
|
||||
throw new Error("We were already showing a single search section: '" + this._searchResultsSingleShownSection
|
||||
+ "' when _showSingleSearchSection() was called for '" + type + "'");
|
||||
}
|
||||
},
|
||||
|
||||
_toggleOnlyDocSearchShown: function() {
|
||||
if (this._docSearchResultsOnlyShown) {
|
||||
this._setAppSearchShown(true);
|
||||
} else {
|
||||
this._setAppSearchShown(false);
|
||||
}
|
||||
},
|
||||
|
||||
_setAppSearchShown: function(show) {
|
||||
if (show) {
|
||||
this._appSearchHeader.actor.show();
|
||||
this._appSearchResultArea.actor.show();
|
||||
this._docSearchResultArea.display.displayPage(0);
|
||||
this._docSearchResultArea.controlBox.hide();
|
||||
this._searchResultsSection.header.setTitle(_("SEARCH RESULTS"));
|
||||
this._searchResultsSection.header.setBackLinkVisible(false);
|
||||
this._searchResultsSection.header.setCountText("");
|
||||
this._docSearchHeader.actor.show();
|
||||
this._docSearchResultsOnlyShown = false;
|
||||
} else {
|
||||
this._appSearchHeader.actor.hide();
|
||||
this._appSearchResultArea.actor.hide();
|
||||
this._appSearchResultArea.display.unsetSelected();
|
||||
this._docSearchResultArea.display.selectFirstItem();
|
||||
this._docSearchResultArea.controlBox.show();
|
||||
this._searchResultsSection.header.setTitle(_("RECENT DOCUMENTS"));
|
||||
this._searchResultsSection.header.setBackLinkVisible(true);
|
||||
let docsCount = this._docSearchResultArea.display.getMatchedItemsCount() + "";
|
||||
this._searchResultsSection.header.setCountText(docsCount);
|
||||
this._docSearchHeader.actor.hide();
|
||||
this._docSearchResultsOnlyShown = true;
|
||||
}
|
||||
},
|
||||
|
||||
_setDocSearchShown: function(show) {
|
||||
if (show) {
|
||||
this._docSearchHeader.actor.show();
|
||||
this._docSearchResultArea.actor.show();
|
||||
this._appSearchResultArea.display.displayPage(0);
|
||||
this._appSearchResultArea.controlBox.hide();
|
||||
this._searchResultsSection.header.setTitle(_("SEARCH RESULTS"));
|
||||
this._searchResultsSection.header.setBackLinkVisible(false);
|
||||
this._searchResultsSection.header.setCountText("");
|
||||
this._appSearchHeader.actor.show();
|
||||
this._appSearchResultsOnlyShown = false;
|
||||
} else {
|
||||
this._docSearchHeader.actor.hide();
|
||||
this._docSearchResultArea.actor.hide();
|
||||
this._docSearchResultArea.display.unsetSelected();
|
||||
this._appSearchResultArea.display.selectFirstItem();
|
||||
this._appSearchResultArea.controlBox.show();
|
||||
this._searchResultsSection.header.setTitle(_("APPLICATIONS"));
|
||||
this._searchResultsSection.header.setBackLinkVisible(true);
|
||||
let appsCount = this._appSearchResultArea.display.getMatchedItemsCount() + "";
|
||||
this._searchResultsSection.header.setCountText(appsCount);
|
||||
this._appSearchHeader.actor.hide();
|
||||
this._appSearchResultsOnlyShown = true;
|
||||
for (var i = 0; i < this._searchSections.length; i++) {
|
||||
let section = this._searchSections[i];
|
||||
if (section.type == type) {
|
||||
// This will be the only section shown.
|
||||
section.resultArea.display.selectFirstItem();
|
||||
section.resultArea.controlBox.show();
|
||||
let itemCount = section.resultArea.display.getMatchedItemsCount();
|
||||
let itemCountText = itemCount + "";
|
||||
section.header.actor.hide();
|
||||
this._searchResultsSection.header.setTitle(section.title);
|
||||
this._searchResultsSection.header.setBackLinkVisible(true);
|
||||
this._searchResultsSection.header.setCountText(itemCountText);
|
||||
} else {
|
||||
// We need to hide this section.
|
||||
section.header.actor.hide();
|
||||
section.resultArea.actor.hide();
|
||||
section.resultArea.display.unsetSelected();
|
||||
}
|
||||
}
|
||||
this._searchResultsSingleShownSection = type;
|
||||
},
|
||||
|
||||
_showAllSearchSections: function() {
|
||||
this._setAppSearchShown(true);
|
||||
this._setDocSearchShown(true);
|
||||
if (this._searchResultsSingleShownSection != null) {
|
||||
let selectionSet = false;
|
||||
for (var i = 0; i < this._searchSections.length; i++) {
|
||||
let section = this._searchSections[i];
|
||||
if (section.type == this._searchResultsSingleShownSection) {
|
||||
// This will no longer be the only section shown.
|
||||
section.resultArea.display.displayPage(0);
|
||||
section.resultArea.controlBox.hide();
|
||||
let itemCount = section.resultArea.display.getMatchedItemsCount();
|
||||
if (itemCount != 0) {
|
||||
section.header.actor.show();
|
||||
section.resultArea.display.selectFirstItem();
|
||||
selectionSet = true;
|
||||
}
|
||||
this._searchResultsSection.header.setTitle(_("SEARCH RESULTS"));
|
||||
this._searchResultsSection.header.setBackLinkVisible(false);
|
||||
this._searchResultsSection.header.setCountText("");
|
||||
} else {
|
||||
// We need to restore this section.
|
||||
let itemCount = section.resultArea.display.getMatchedItemsCount();
|
||||
if (itemCount != 0) {
|
||||
section.header.actor.show();
|
||||
section.resultArea.actor.show();
|
||||
// This ensures that some other section will have the selection if the
|
||||
// single section that was being displayed did not have any items.
|
||||
if (!selectionSet) {
|
||||
section.resultArea.display.selectFirstItem();
|
||||
selectionSet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this._searchResultsSingleShownSection = null;
|
||||
}
|
||||
},
|
||||
|
||||
_findAnotherSectionWithItems: function(index, increment) {
|
||||
let pos = _getIndexWrapped(index, increment, this._searchSections.length);
|
||||
while (pos != index) {
|
||||
if (this._searchSections[pos].resultArea.display.hasItems())
|
||||
return pos;
|
||||
pos = _getIndexWrapped(pos, increment, this._searchSections.length);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(Dash.prototype);
|
||||
|
@ -102,7 +102,7 @@ DocDisplayItem.prototype = {
|
||||
_resetTimeDisplay: function(currentSecs) {
|
||||
let lastSecs = this._docInfo.timestamp;
|
||||
let timeDelta = currentSecs - lastSecs;
|
||||
let [text, nextUpdate] = Shell.Global.get().format_time_relative_pretty(timeDelta);
|
||||
let [text, nextUpdate] = global.format_time_relative_pretty(timeDelta);
|
||||
this._timeoutTime = currentSecs + nextUpdate;
|
||||
this._setDescriptionText(text);
|
||||
}
|
||||
@ -120,8 +120,6 @@ DocDisplay.prototype = {
|
||||
|
||||
_init : function() {
|
||||
GenericDisplay.GenericDisplay.prototype._init.call(this);
|
||||
let me = this;
|
||||
|
||||
// We keep a single timeout callback for updating last visited times
|
||||
// for all the items in the display. This avoids creating individual
|
||||
// callbacks for each item in the display. So proper time updates
|
||||
@ -132,14 +130,14 @@ DocDisplay.prototype = {
|
||||
|
||||
this._docManager = DocInfo.getDocManager();
|
||||
this._docsStale = true;
|
||||
this._docManager.connect('changed', function(mgr, userData) {
|
||||
me._docsStale = true;
|
||||
this._docManager.connect('changed', Lang.bind(this, function(mgr, userData) {
|
||||
this._docsStale = true;
|
||||
// Changes in local recent files should not happen when we are in the Overview mode,
|
||||
// but redisplaying right away is cool when we use Zephyr.
|
||||
// Also, we might be displaying remote documents, like Google Docs, in the future
|
||||
// which might be edited by someone else.
|
||||
me._redisplay(false);
|
||||
});
|
||||
this._redisplay(false);
|
||||
}));
|
||||
|
||||
this.connect('destroy', Lang.bind(this, function (o) {
|
||||
if (this._updateTimeoutId > 0)
|
||||
|
32
js/ui/environment.js
Normal file
32
js/ui/environment.js
Normal 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();
|
||||
}
|
@ -88,7 +88,6 @@ GenericDisplayItem.prototype = {
|
||||
spacing: DEFAULT_PADDING });
|
||||
this._infoContent.append(this._infoText, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
let global = Shell.Global.get();
|
||||
let infoIconUri = "file://" + global.imagedir + "info.svg";
|
||||
let infoIcon = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER,
|
||||
infoIconUri,
|
||||
@ -502,7 +501,6 @@ GenericDisplay.prototype = {
|
||||
Mainloop.idle_add(Lang.bind(this,
|
||||
function() {
|
||||
let [child, x, y, mask] = Gdk.Screen.get_default().get_root_window().get_pointer();
|
||||
let global = Shell.Global.get();
|
||||
let actor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE,
|
||||
x, y);
|
||||
if (actor != null) {
|
||||
@ -709,6 +707,9 @@ GenericDisplay.prototype = {
|
||||
if (resetDisplayControl) {
|
||||
this.displayControl.remove_all();
|
||||
let nPages = this._list.n_pages;
|
||||
// Don't show the page indicator if there is only one page.
|
||||
if (nPages == 1)
|
||||
return;
|
||||
let pageNumber = this._list.page;
|
||||
for (let i = 0; i < nPages; i++) {
|
||||
let pageControl = new Link.Link({ color: (i == pageNumber) ? DISPLAY_CONTROL_SELECTED_COLOR : ITEM_DISPLAY_DESCRIPTION_COLOR,
|
||||
|
@ -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; " +
|
||||
@ -35,7 +25,6 @@ var commandHeader = "const Clutter = imports.gi.Clutter; " +
|
||||
"const Tweener = imports.ui.tweener; " +
|
||||
/* Utility functions...we should probably be able to use these
|
||||
* in the shell core code too. */
|
||||
"const global = Shell.Global.get(); " +
|
||||
"const stage = global.stage; " +
|
||||
"const color = function(pixel) { let c= new Clutter.Color(); c.from_pixel(pixel); return c; }; " +
|
||||
/* Special lookingGlass functions */
|
||||
@ -48,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 });
|
||||
@ -59,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);
|
||||
},
|
||||
@ -81,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;
|
||||
},
|
||||
|
||||
@ -96,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);
|
||||
},
|
||||
@ -109,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;
|
||||
@ -131,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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,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;
|
||||
@ -182,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);
|
||||
@ -215,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;
|
||||
@ -234,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,22 +230,17 @@ function Inspector() {
|
||||
|
||||
Inspector.prototype = {
|
||||
_init: function() {
|
||||
let global = Shell.Global.get();
|
||||
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;
|
||||
@ -274,7 +250,6 @@ Inspector.prototype = {
|
||||
}));
|
||||
|
||||
eventHandler.connect('button-press-event', Lang.bind(this, function (actor, event) {
|
||||
let global = Shell.Global.get();
|
||||
Clutter.ungrab_pointer(eventHandler);
|
||||
|
||||
let [stageX, stageY] = event.get_coords();
|
||||
@ -288,7 +263,6 @@ Inspector.prototype = {
|
||||
}));
|
||||
|
||||
eventHandler.connect('motion-event', Lang.bind(this, function (actor, event) {
|
||||
let global = Shell.Global.get();
|
||||
let [stageX, stageY] = event.get_coords();
|
||||
let target = global.stage.get_actor_at_pos(Clutter.PickMode.ALL,
|
||||
stageX,
|
||||
@ -312,8 +286,6 @@ function LookingGlass() {
|
||||
|
||||
LookingGlass.prototype = {
|
||||
_init : function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
this._idleHistorySaveId = 0;
|
||||
let historyPath = global.configdir + "/lookingglass-history.txt";
|
||||
this._historyFile = Gio.file_new_for_path(historyPath);
|
||||
@ -327,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();
|
||||
@ -367,32 +336,27 @@ 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: ''});
|
||||
/* kind of a hack */
|
||||
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)
|
||||
global.stage.set_key_focus(this._entry);
|
||||
@ -409,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.
|
||||
@ -422,8 +386,8 @@ LookingGlass.prototype = {
|
||||
this._historyNavIndex = -1;
|
||||
return true;
|
||||
}));
|
||||
this._entry.connect('key-press-event', Lang.bind(this, function(o, e) {
|
||||
let symbol = Shell.get_event_key_symbol(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();
|
||||
return true;
|
||||
@ -452,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;
|
||||
@ -524,8 +501,7 @@ LookingGlass.prototype = {
|
||||
},
|
||||
|
||||
_resizeTo: function(actor) {
|
||||
let stage = Shell.Global.get().stage;
|
||||
let stageWidth = stage.width;
|
||||
let stage = global.stage;
|
||||
let myWidth = stage.width * 0.7;
|
||||
let myHeight = stage.height * 0.7;
|
||||
let [srcX, srcY] = actor.get_transformed_position();
|
||||
@ -555,10 +531,7 @@ LookingGlass.prototype = {
|
||||
|
||||
Tweener.removeTweens(this.actor);
|
||||
|
||||
if (!Main.beginModal())
|
||||
return;
|
||||
|
||||
let global = Shell.Global.get();
|
||||
Main.pushModal(this.actor);
|
||||
global.stage.set_key_focus(this._entry);
|
||||
|
||||
Tweener.addTween(this.actor, { time: 0.5,
|
||||
@ -575,7 +548,7 @@ LookingGlass.prototype = {
|
||||
this._open = false;
|
||||
Tweener.removeTweens(this.actor);
|
||||
|
||||
Main.endModal();
|
||||
Main.popModal(this.actor);
|
||||
|
||||
Tweener.addTween(this.actor, { time: 0.5,
|
||||
transition: "easeOutQuad",
|
||||
|
135
js/ui/main.js
135
js/ui/main.js
@ -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();
|
||||
@ -30,16 +31,20 @@ let runDialog = null;
|
||||
let lookingGlass = null;
|
||||
let wm = null;
|
||||
let recorder = null;
|
||||
let inModal = false;
|
||||
let modalCount = 0;
|
||||
let modalActorFocusStack = [];
|
||||
|
||||
function start() {
|
||||
let global = Shell.Global.get();
|
||||
// Add a binding for "global" in the global JS namespace; (gjs
|
||||
// keeps the web browser convention of having that namespace be
|
||||
// called "window".)
|
||||
window.global = Shell.Global.get();
|
||||
|
||||
Gio.DesktopAppInfo.set_desktop_env("GNOME");
|
||||
|
||||
global.grab_dbus_service();
|
||||
|
||||
Tweener.init();
|
||||
Environment.init();
|
||||
|
||||
// Ensure ShellAppMonitor is initialized; this will
|
||||
// also initialize ShellAppSystem first. ShellAppSystem
|
||||
@ -62,12 +67,14 @@ 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.
|
||||
if (runDialog == null) {
|
||||
runDialog = new RunDialog.RunDialog();
|
||||
}
|
||||
runDialog.open();
|
||||
getRunDialog().open();
|
||||
});
|
||||
|
||||
overview = new Overview.Overview();
|
||||
@ -102,7 +109,6 @@ function start() {
|
||||
}
|
||||
|
||||
function _relayout() {
|
||||
let global = Shell.Global.get();
|
||||
panel.actor.set_size(global.screen_width, Panel.PANEL_HEIGHT);
|
||||
overview.relayout();
|
||||
}
|
||||
@ -114,8 +120,6 @@ function _relayout() {
|
||||
// is called.)
|
||||
function _removeUnusedWorkspaces() {
|
||||
|
||||
let global = Shell.Global.get();
|
||||
|
||||
let windows = global.get_windows();
|
||||
let maxWorkspace = 0;
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
@ -149,13 +153,13 @@ function _removeUnusedWorkspaces() {
|
||||
// should be asking Mutter to resolve the key into an action and then
|
||||
// base our handling based on the action.
|
||||
function _globalKeyPressHandler(actor, event) {
|
||||
if (!inModal)
|
||||
if (modalCount == 0)
|
||||
return false;
|
||||
|
||||
let type = event.type();
|
||||
|
||||
if (type == Clutter.EventType.KEY_PRESS) {
|
||||
let symbol = Shell.get_event_key_symbol (event);
|
||||
let symbol = event.get_key_symbol();
|
||||
if (symbol == Clutter.Print) {
|
||||
// We want to be able to take screenshots of the shell at all times
|
||||
let gconf = Shell.GConf.get_default();
|
||||
@ -169,7 +173,7 @@ function _globalKeyPressHandler(actor, event) {
|
||||
return true;
|
||||
}
|
||||
} else if (type == Clutter.EventType.KEY_RELEASE) {
|
||||
let symbol = Shell.get_event_key_symbol (event);
|
||||
let symbol = event.get_key_symbol();
|
||||
if (symbol == Clutter.Super_L || symbol == Clutter.Super_R) {
|
||||
// The super key is the default for triggering the overview, and should
|
||||
// get us out of the overview when we are already in it.
|
||||
@ -177,35 +181,96 @@ function _globalKeyPressHandler(actor, event) {
|
||||
overview.hide();
|
||||
|
||||
return true;
|
||||
} else if (symbol == Clutter.F2 && (event.get_state() & Clutter.ModifierType.MOD1_MASK)) {
|
||||
getRunDialog().open();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Used to go into a mode where all keyboard and mouse input goes to
|
||||
// the stage. Returns true if we successfully grabbed the keyboard and
|
||||
// went modal, false otherwise
|
||||
function beginModal() {
|
||||
let global = Shell.Global.get();
|
||||
let timestamp = global.screen.get_display().get_current_time();
|
||||
|
||||
if (!global.begin_modal(timestamp))
|
||||
return false;
|
||||
global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
|
||||
|
||||
inModal = true;
|
||||
|
||||
return true;
|
||||
function _findModal(actor) {
|
||||
for (let i = 0; i < modalActorFocusStack.length; i++) {
|
||||
let [stackActor, stackFocus] = modalActorFocusStack[i];
|
||||
if (stackActor == actor) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function endModal() {
|
||||
let global = Shell.Global.get();
|
||||
/**
|
||||
* pushModal:
|
||||
* @actor: #ClutterActor which will be given keyboard focus
|
||||
*
|
||||
* Ensure we are in a mode where all keyboard and mouse input goes to
|
||||
* the stage. Multiple calls to this function act in a stacking fashion;
|
||||
* the effect will be undone when an equal number of popModal() invocations
|
||||
* have been made.
|
||||
*
|
||||
* Next, record the current Clutter keyboard focus on a stack. If the modal stack
|
||||
* returns to this actor, reset the focus to the actor which was focused
|
||||
* at the time pushModal() was invoked.
|
||||
*/
|
||||
function pushModal(actor) {
|
||||
let timestamp = global.screen.get_display().get_current_time();
|
||||
|
||||
modalCount += 1;
|
||||
actor.connect('destroy', function() {
|
||||
let index = _findModal(actor);
|
||||
if (index >= 0)
|
||||
modalActorFocusStack.splice(index, 1);
|
||||
});
|
||||
let curFocus = global.stage.get_key_focus();
|
||||
if (curFocus != null) {
|
||||
curFocus.connect('destroy', function() {
|
||||
let index = _findModal(actor);
|
||||
if (index >= 0)
|
||||
modalActorFocusStack[index][1] = null;
|
||||
});
|
||||
}
|
||||
modalActorFocusStack.push([actor, curFocus]);
|
||||
|
||||
if (modalCount > 1)
|
||||
return;
|
||||
|
||||
if (!global.begin_modal(timestamp)) {
|
||||
log("pushModal: invocation of begin_modal failed");
|
||||
return;
|
||||
}
|
||||
global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* popModal:
|
||||
* @actor: #ClutterActor passed to original invocation of pushModal().
|
||||
*
|
||||
* Reverse the effect of pushModal(). If this invocation is undoing
|
||||
* the topmost invocation, then the focus will be restored to the
|
||||
* previous focus at the time when pushModal() was invoked.
|
||||
*/
|
||||
function popModal(actor) {
|
||||
let timestamp = global.screen.get_display().get_current_time();
|
||||
|
||||
modalCount -= 1;
|
||||
let focusIndex = _findModal(actor);
|
||||
if (focusIndex >= 0) {
|
||||
if (focusIndex == modalActorFocusStack.length - 1) {
|
||||
let [stackActor, stackFocus] = modalActorFocusStack[focusIndex];
|
||||
global.stage.set_key_focus(stackFocus);
|
||||
} else {
|
||||
// Remove from the middle, shift the focus chain up
|
||||
for (let i = focusIndex; i < modalActorFocusStack.length - 1; i++) {
|
||||
modalActorFocusStack[i + 1][1] = modalActorFocusStack[i][1];
|
||||
}
|
||||
}
|
||||
modalActorFocusStack.splice(focusIndex, 1);
|
||||
}
|
||||
if (modalCount > 0)
|
||||
return;
|
||||
|
||||
global.end_modal(timestamp);
|
||||
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
|
||||
inModal = false;
|
||||
}
|
||||
|
||||
function createLookingGlass() {
|
||||
@ -216,8 +281,14 @@ function createLookingGlass() {
|
||||
return lookingGlass;
|
||||
}
|
||||
|
||||
function getRunDialog() {
|
||||
if (runDialog == null) {
|
||||
runDialog = new RunDialog.RunDialog();
|
||||
}
|
||||
return runDialog;
|
||||
}
|
||||
|
||||
function createAppLaunchContext() {
|
||||
let global = Shell.Global.get();
|
||||
let screen = global.screen;
|
||||
let display = screen.get_display();
|
||||
|
||||
|
@ -73,6 +73,7 @@ const NUMBER_OF_SECTIONS_IN_SEARCH = 2;
|
||||
let wideScreen = false;
|
||||
let displayGridColumnWidth = null;
|
||||
let displayGridRowHeight = null;
|
||||
let addRemoveButtonSize = null;
|
||||
|
||||
function Overview() {
|
||||
this._init();
|
||||
@ -80,10 +81,6 @@ function Overview() {
|
||||
|
||||
Overview.prototype = {
|
||||
_init : function() {
|
||||
let me = this;
|
||||
|
||||
let global = Shell.Global.get();
|
||||
|
||||
this._group = new Clutter.Group();
|
||||
this._group._delegate = this;
|
||||
|
||||
@ -95,7 +92,15 @@ Overview.prototype = {
|
||||
|
||||
this._activeDisplayPane = null;
|
||||
|
||||
// Used to catch any clicks when we have an active pane; see the comments
|
||||
// During transitions, we raise this to the top to avoid having the overview
|
||||
// area be reactive; it causes too many issues such as double clicks on
|
||||
// Dash elements, or mouseover handlers in the workspaces.
|
||||
this._coverPane = new Clutter.Rectangle({ opacity: 0,
|
||||
reactive: true });
|
||||
this._group.add_actor(this._coverPane);
|
||||
this._coverPane.connect('event', Lang.bind(this, function (actor, event) { return true; }));
|
||||
|
||||
// Similar to the cover pane but used for dialogs ("panes"); see the comments
|
||||
// in addPane below.
|
||||
this._transparentBackground = new Clutter.Rectangle({ opacity: 0,
|
||||
reactive: true });
|
||||
@ -127,12 +132,12 @@ Overview.prototype = {
|
||||
this._transparentBackground.lower_bottom();
|
||||
this._paneContainer.lower_bottom();
|
||||
|
||||
this._coverPane.lower_bottom();
|
||||
|
||||
this._workspaces = null;
|
||||
},
|
||||
|
||||
_recalculateGridSizes: function () {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
wideScreen = (global.screen_width/global.screen_height > WIDE_SCREEN_CUT_OFF_RATIO);
|
||||
|
||||
// We divide the screen into an imaginary grid which helps us determine the layout of
|
||||
@ -147,12 +152,14 @@ Overview.prototype = {
|
||||
},
|
||||
|
||||
relayout: function () {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
let screenHeight = global.screen_height;
|
||||
let screenWidth = global.screen_width;
|
||||
|
||||
let contentHeight = screenHeight - Panel.PANEL_HEIGHT;
|
||||
let contentY = Panel.PANEL_HEIGHT;
|
||||
let contentHeight = screenHeight - contentY;
|
||||
|
||||
this._coverPane.set_position(0, contentY);
|
||||
this._coverPane.set_size(screenWidth, contentHeight);
|
||||
|
||||
let workspaceColumnsUsed = wideScreen ? COLUMNS_FOR_WORKSPACES_WIDE_SCREEN : COLUMNS_FOR_WORKSPACES_REGULAR_SCREEN;
|
||||
let workspaceRowsUsed = wideScreen ? ROWS_FOR_WORKSPACES_WIDE_SCREEN : ROWS_FOR_WORKSPACES_REGULAR_SCREEN;
|
||||
@ -167,22 +174,21 @@ Overview.prototype = {
|
||||
this._workspacesX = displayGridColumnWidth + WORKSPACE_GRID_PADDING;
|
||||
this._workspacesY = displayGridRowHeight + WORKSPACE_GRID_PADDING * (screenHeight / screenWidth);
|
||||
|
||||
let dashY = Panel.PANEL_HEIGHT;
|
||||
this._dash.actor.set_position(0, dashY);
|
||||
this._dash.actor.set_size(displayGridColumnWidth, screenHeight - dashY);
|
||||
this._dash.searchArea.height = this._workspacesY - dashY;
|
||||
this._dash.actor.set_position(0, contentY);
|
||||
this._dash.actor.set_size(displayGridColumnWidth, contentHeight);
|
||||
this._dash.searchArea.height = this._workspacesY - contentY;
|
||||
this._dash.sectionArea.height = this._workspacesHeight;
|
||||
|
||||
// place the 'Add Workspace' button in the bottom row of the grid
|
||||
this._addButtonSize = Math.floor(displayGridRowHeight * 3/5);
|
||||
this._addButtonX = this._workspacesX + this._workspacesWidth - this._addButtonSize;
|
||||
addRemoveButtonSize = Math.floor(displayGridRowHeight * 3/5);
|
||||
this._addButtonX = this._workspacesX + this._workspacesWidth - addRemoveButtonSize;
|
||||
this._addButtonY = screenHeight - Math.floor(displayGridRowHeight * 4/5);
|
||||
|
||||
this._backOver.set_position(0, Panel.PANEL_HEIGHT);
|
||||
this._backOver.set_position(0, contentY);
|
||||
this._backOver.set_size(global.screen_width, contentHeight);
|
||||
|
||||
this._paneContainer.set_position(this._dash.actor.x + this._dash.actor.width + DEFAULT_PADDING,
|
||||
Panel.PANEL_HEIGHT);
|
||||
contentY);
|
||||
// Dynamic width
|
||||
this._paneContainer.height = contentHeight;
|
||||
|
||||
@ -232,7 +238,7 @@ Overview.prototype = {
|
||||
// This allows the user to place the item on any workspace.
|
||||
handleDragOver : function(source, actor, x, y, time) {
|
||||
if (source instanceof GenericDisplay.GenericDisplayItem
|
||||
|| source instanceof AppDisplay.WellDisplayItem) {
|
||||
|| source instanceof AppDisplay.BaseWellItem) {
|
||||
if (this._activeDisplayPane != null)
|
||||
this._activeDisplayPane.close();
|
||||
return true;
|
||||
@ -271,20 +277,16 @@ Overview.prototype = {
|
||||
show : function() {
|
||||
if (this.visible)
|
||||
return;
|
||||
if (!Main.beginModal())
|
||||
return;
|
||||
Main.pushModal(this._dash.actor);
|
||||
|
||||
this.visible = true;
|
||||
this.animationInProgress = true;
|
||||
|
||||
let global = Shell.Global.get();
|
||||
|
||||
this._dash.show();
|
||||
|
||||
/* TODO: make this stuff dynamic */
|
||||
this._workspaces = new Workspaces.Workspaces(this._workspacesWidth, this._workspacesHeight,
|
||||
this._workspacesX, this._workspacesY,
|
||||
this._addButtonSize, this._addButtonX, this._addButtonY);
|
||||
this._workspacesX, this._workspacesY);
|
||||
this._group.add_actor(this._workspaces.actor);
|
||||
|
||||
// The workspaces actor is as big as the screen, so we have to raise the dash above it
|
||||
@ -292,6 +294,12 @@ Overview.prototype = {
|
||||
// be as big as the screen.
|
||||
this._dash.actor.raise(this._workspaces.actor);
|
||||
|
||||
// Create (+) button
|
||||
this._addButton = new AddWorkspaceButton(addRemoveButtonSize, this._addButtonX, this._addButtonY, Lang.bind(this, this._acceptNewWorkspaceDrop));
|
||||
this._addButton.actor.connect('button-release-event', Lang.bind(this, this._addNewWorkspace));
|
||||
this._group.add_actor(this._addButton.actor);
|
||||
this._addButton.actor.raise(this._workspaces.actor);
|
||||
|
||||
// All the the actors in the window group are completely obscured,
|
||||
// hiding the group holding them while the Overview is displayed greatly
|
||||
// increases performance of the Overview especially when there are many
|
||||
@ -327,15 +335,14 @@ Overview.prototype = {
|
||||
time: ANIMATION_TIME
|
||||
});
|
||||
|
||||
this._coverPane.raise_top();
|
||||
this.emit('showing');
|
||||
},
|
||||
|
||||
hide : function() {
|
||||
hide: function() {
|
||||
if (!this.visible || this._hideInProgress)
|
||||
return;
|
||||
|
||||
let global = Shell.Global.get();
|
||||
|
||||
this.animationInProgress = true;
|
||||
this._hideInProgress = true;
|
||||
if (this._activeDisplayPane != null)
|
||||
@ -365,6 +372,7 @@ Overview.prototype = {
|
||||
time: ANIMATION_TIME
|
||||
});
|
||||
|
||||
this._coverPane.raise_top();
|
||||
this.emit('hiding');
|
||||
},
|
||||
|
||||
@ -375,6 +383,18 @@ Overview.prototype = {
|
||||
this.show();
|
||||
},
|
||||
|
||||
/**
|
||||
* getWorkspacesForWindow:
|
||||
* @metaWindow: A #MetaWindow
|
||||
*
|
||||
* Returns the Workspaces object associated with the given window.
|
||||
* This method is not be accessible if the overview is not open
|
||||
* and will return %null.
|
||||
*/
|
||||
getWorkspacesForWindow: function(metaWindow) {
|
||||
return this._workspaces;
|
||||
},
|
||||
|
||||
/**
|
||||
* activateWindow:
|
||||
* @metaWindow: A #MetaWindow
|
||||
@ -387,7 +407,6 @@ Overview.prototype = {
|
||||
*/
|
||||
activateWindow: function (metaWindow, time) {
|
||||
this._workspaces.activateWindowFromOverview(metaWindow, time);
|
||||
this.hide();
|
||||
},
|
||||
|
||||
//// Private methods ////
|
||||
@ -397,13 +416,12 @@ Overview.prototype = {
|
||||
return;
|
||||
|
||||
this.animationInProgress = false;
|
||||
this._coverPane.lower_bottom();
|
||||
|
||||
this.emit('shown');
|
||||
},
|
||||
|
||||
_hideDone: function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
global.window_group.show();
|
||||
|
||||
this._workspaces.destroy();
|
||||
@ -416,8 +434,47 @@ Overview.prototype = {
|
||||
this.animationInProgress = false;
|
||||
this._hideInProgress = false;
|
||||
|
||||
Main.endModal();
|
||||
this._coverPane.lower_bottom();
|
||||
|
||||
Main.popModal(this._dash.actor);
|
||||
this.emit('hidden');
|
||||
},
|
||||
|
||||
_addNewWorkspace: function() {
|
||||
global.screen.append_new_workspace(false, global.screen.get_display().get_current_time());
|
||||
},
|
||||
|
||||
_acceptNewWorkspaceDrop: function(source, dropActor, x, y, time) {
|
||||
this._addNewWorkspace();
|
||||
return this._workspaces.acceptNewWorkspaceDrop(source, dropActor, x, y, time);
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(Overview.prototype);
|
||||
|
||||
function AddWorkspaceButton(buttonSize, buttonX, buttonY, acceptDropCallback) {
|
||||
this._init(buttonSize, buttonX, buttonY, acceptDropCallback);
|
||||
}
|
||||
|
||||
AddWorkspaceButton.prototype = {
|
||||
_init: function(buttonSize, buttonX, buttonY, acceptDropCallback) {
|
||||
this.actor = new Clutter.Group({ x: buttonX,
|
||||
y: buttonY,
|
||||
width: global.screen_width - buttonX,
|
||||
height: global.screen_height - buttonY,
|
||||
reactive: true });
|
||||
this.actor._delegate = this;
|
||||
this._acceptDropCallback = acceptDropCallback;
|
||||
|
||||
let plus = new Clutter.Texture({ x: 0,
|
||||
y: 0,
|
||||
width: buttonSize,
|
||||
height: buttonSize });
|
||||
plus.set_from_file(global.imagedir + 'add-workspace.svg');
|
||||
this.actor.add_actor(plus);
|
||||
},
|
||||
|
||||
// Draggable target interface
|
||||
acceptDrop: function(source, actor, x, y, time) {
|
||||
return this._acceptDropCallback(source, actor, x, y, time);
|
||||
}
|
||||
};
|
||||
|
@ -66,7 +66,7 @@ function AppPanelMenu() {
|
||||
|
||||
AppPanelMenu.prototype = {
|
||||
_init: function() {
|
||||
this._metaDisplay = Shell.Global.get().screen.get_display();
|
||||
this._metaDisplay = global.screen.get_display();
|
||||
|
||||
this._focusedApp = null;
|
||||
this._activeSequence = null;
|
||||
@ -168,8 +168,6 @@ function Panel() {
|
||||
|
||||
Panel.prototype = {
|
||||
_init : function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL
|
||||
});
|
||||
@ -474,14 +472,14 @@ Panel.prototype = {
|
||||
},
|
||||
|
||||
_onHotCornerLeft : function(actor, event) {
|
||||
if (Shell.get_event_related(event) != this._hotCornerEnvirons) {
|
||||
if (event.get_related() != this._hotCornerEnvirons) {
|
||||
this._hotCornerEntered = false;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_onHotCornerEnvironsLeft : function(actor, event) {
|
||||
if (Shell.get_event_related(event) != this._hotCorner) {
|
||||
if (event.get_related() != this._hotCorner) {
|
||||
this._hotCornerEntered = false;
|
||||
}
|
||||
return false;
|
||||
|
@ -5,6 +5,7 @@ const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
@ -21,8 +22,10 @@ BOX_BACKGROUND_COLOR.from_pixel(0x000000cc);
|
||||
const BOX_TEXT_COLOR = new Clutter.Color();
|
||||
BOX_TEXT_COLOR.from_pixel(0xffffffff);
|
||||
|
||||
const BOX_WIDTH = 320;
|
||||
const BOX_HEIGHT = 56;
|
||||
const DIALOG_WIDTH = 320;
|
||||
const DIALOG_PADDING = 6;
|
||||
const ICON_SIZE = 24;
|
||||
const ICON_BOX_SIZE = 36;
|
||||
|
||||
function RunDialog() {
|
||||
this._init();
|
||||
@ -30,25 +33,31 @@ function RunDialog() {
|
||||
|
||||
RunDialog.prototype = {
|
||||
_init : function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
this._isOpen = false;
|
||||
|
||||
let gconf = Shell.GConf.get_default();
|
||||
gconf.connect('changed', Lang.bind(this, function (gconf, key) {
|
||||
if (key == 'development_tools')
|
||||
this._enableInternalCommands = gconf.get_bool('development_tools');
|
||||
}));
|
||||
this._enableInternalCommands = gconf.get_boolean('development_tools');
|
||||
|
||||
this._internalCommands = { 'lg':
|
||||
Lang.bind(this, function() {
|
||||
// Run in an idle to avoid recursive key grab problems
|
||||
Mainloop.idle_add(function() { Main.createLookingGlass().open(); });
|
||||
Main.createLookingGlass().open();
|
||||
}),
|
||||
|
||||
'r': Lang.bind(this, function() {
|
||||
let global = Shell.Global.get();
|
||||
global.reexec_self();
|
||||
}),
|
||||
|
||||
// Developer brain backwards compatibility
|
||||
'restart': Lang.bind(this, function() {
|
||||
let global = Shell.Global.get();
|
||||
global.reexec_self();
|
||||
}),
|
||||
|
||||
'debugexit': Lang.bind(this, function() {
|
||||
Meta.exit(Meta.ExitCode.ERROR);
|
||||
})
|
||||
};
|
||||
|
||||
@ -64,45 +73,77 @@ RunDialog.prototype = {
|
||||
reactive: true });
|
||||
this._group.add_actor(this._overlay);
|
||||
|
||||
let boxGroup = new Clutter.Group();
|
||||
boxGroup.set_position((global.screen_width - BOX_WIDTH) / 2,
|
||||
(global.screen_height - BOX_HEIGHT) / 2);
|
||||
this._group.add_actor(boxGroup);
|
||||
let boxH = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
x_align: Big.BoxAlignment.CENTER,
|
||||
y_align: Big.BoxAlignment.CENTER,
|
||||
width: global.screen_width,
|
||||
height: global.screen_height });
|
||||
|
||||
let box = new Big.Box({ background_color: BOX_BACKGROUND_COLOR,
|
||||
corner_radius: 4,
|
||||
reactive: false,
|
||||
width: BOX_WIDTH,
|
||||
height: BOX_HEIGHT
|
||||
});
|
||||
boxGroup.add_actor(box);
|
||||
this._group.add_actor(boxH);
|
||||
|
||||
let boxV = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
y_align: Big.BoxAlignment.CENTER });
|
||||
|
||||
boxH.append(boxV, Big.BoxPackFlags.NONE);
|
||||
|
||||
|
||||
let dialogBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
background_color: BOX_BACKGROUND_COLOR,
|
||||
corner_radius: 4,
|
||||
reactive: false,
|
||||
padding: DIALOG_PADDING,
|
||||
width: DIALOG_WIDTH });
|
||||
|
||||
boxH.append(dialogBox, Big.BoxPackFlags.NONE);
|
||||
|
||||
let label = new Clutter.Text({ color: BOX_TEXT_COLOR,
|
||||
font_name: '18px Sans',
|
||||
text: _("Please enter a command:") });
|
||||
label.set_position(6, 6);
|
||||
boxGroup.add_actor(label);
|
||||
|
||||
dialogBox.append(label, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this._entry = new Clutter.Text({ color: BOX_TEXT_COLOR,
|
||||
font_name: '20px Sans Bold',
|
||||
editable: true,
|
||||
activatable: true,
|
||||
singleLineMode: true,
|
||||
text: '',
|
||||
width: BOX_WIDTH - 12,
|
||||
height: BOX_HEIGHT - 12 });
|
||||
// TODO: Implement relative positioning using Tidy.
|
||||
this._entry.set_position(6, 30);
|
||||
boxGroup.add_actor(this._entry);
|
||||
singleLineMode: true });
|
||||
|
||||
dialogBox.append(this._entry, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this._errorBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
padding_top: DIALOG_PADDING });
|
||||
|
||||
dialogBox.append(this._errorBox, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
let iconBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
y_align: Big.BoxAlignment.CENTER,
|
||||
x_align: Big.BoxAlignment.CENTER,
|
||||
width: ICON_BOX_SIZE,
|
||||
height: ICON_BOX_SIZE });
|
||||
|
||||
this._errorBox.append(iconBox, Big.BoxPackFlags.NONE);
|
||||
|
||||
this._commandError = false;
|
||||
|
||||
let errorIcon = Shell.TextureCache.get_default().load_icon_name("gtk-dialog-error", ICON_SIZE);
|
||||
iconBox.append(errorIcon, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this._errorMessage = new Clutter.Text({ color: BOX_TEXT_COLOR,
|
||||
font_name: '18px Sans Bold',
|
||||
line_wrap: true });
|
||||
|
||||
this._errorBox.append(this._errorMessage, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this._errorBox.hide();
|
||||
|
||||
this._entry.connect('activate', Lang.bind(this, function (o, e) {
|
||||
this._run(o.get_text());
|
||||
this.close();
|
||||
return false;
|
||||
if (!this._commandError)
|
||||
this.close();
|
||||
}));
|
||||
|
||||
|
||||
this._entry.connect('key-press-event', Lang.bind(this, function(o, e) {
|
||||
let symbol = Shell.get_event_key_symbol(e);
|
||||
let symbol = e.get_key_symbol();
|
||||
if (symbol == Clutter.Escape) {
|
||||
this.close();
|
||||
return true;
|
||||
@ -112,17 +153,31 @@ RunDialog.prototype = {
|
||||
},
|
||||
|
||||
_run : function(command) {
|
||||
let f = this._internalCommands[command];
|
||||
let f;
|
||||
if (this._enableInternalCommands)
|
||||
f = this._internalCommands[command];
|
||||
else
|
||||
f = null;
|
||||
if (f) {
|
||||
f();
|
||||
} else if (command) {
|
||||
try {
|
||||
this._commandError = false;
|
||||
let [ok, len, args] = GLib.shell_parse_argv(command);
|
||||
let p = new Shell.Process({'args' : args});
|
||||
p.run();
|
||||
} catch (e) {
|
||||
// TODO: Give the user direct feedback.
|
||||
log('Could not run command ' + command + ': ' + e);
|
||||
this._commandError = true;
|
||||
/*
|
||||
* The exception contains an error string like:
|
||||
* Error invoking Shell.run: Failed to execute child process "foo"
|
||||
* (No such file or directory)
|
||||
* We are only interested in the actual error, so parse that out.
|
||||
*/
|
||||
let m = /.+\((.+)\)/.exec(e);
|
||||
let errorStr = "Execution of '" + command + "' failed:\n" + m[1];
|
||||
this._errorMessage.set_text(errorStr);
|
||||
this._errorBox.show();
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -131,13 +186,10 @@ RunDialog.prototype = {
|
||||
if (this._isOpen) // Already shown
|
||||
return;
|
||||
|
||||
if (!Main.beginModal())
|
||||
return;
|
||||
|
||||
this._isOpen = true;
|
||||
this._group.show();
|
||||
|
||||
let global = Shell.Global.get();
|
||||
Main.pushModal(this._group);
|
||||
global.stage.set_key_focus(this._entry);
|
||||
},
|
||||
|
||||
@ -147,10 +199,13 @@ RunDialog.prototype = {
|
||||
|
||||
this._isOpen = false;
|
||||
|
||||
this._errorBox.hide();
|
||||
this._commandError = false;
|
||||
|
||||
this._group.hide();
|
||||
this._entry.text = '';
|
||||
|
||||
Main.endModal();
|
||||
Main.popModal(this._group);
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(RunDialog.prototype);
|
||||
|
@ -21,21 +21,12 @@ const SIDEBAR_PADDING = 4;
|
||||
const SIDEBAR_COLLAPSED_WIDTH = Widget.COLLAPSED_WIDTH + 3 * WidgetBox.WIDGETBOX_PADDING + SIDEBAR_PADDING;
|
||||
const SIDEBAR_EXPANDED_WIDTH = Widget.EXPANDED_WIDTH + 3 * WidgetBox.WIDGETBOX_PADDING + SIDEBAR_PADDING;
|
||||
|
||||
// The maximum height of the sidebar would be extending from just
|
||||
// below the panel to just above the taskbar. Since the taskbar is
|
||||
// just a temporary hack and it would be too hard to do this the right
|
||||
// way, we just hardcode its size.
|
||||
const HARDCODED_TASKBAR_HEIGHT = 24;
|
||||
const MAXIMUM_SIDEBAR_HEIGHT = Shell.Global.get().screen_height - Panel.PANEL_HEIGHT - HARDCODED_TASKBAR_HEIGHT;
|
||||
|
||||
function Sidebar() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
Sidebar.prototype = {
|
||||
_init : function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
// The top-left corner of the sidebar is fixed at:
|
||||
// x = -WidgetBox.WIDGETBOX_PADDING, y = Panel.PANEL_HEIGHT.
|
||||
// (The negative X is so that we don't see the rounded
|
||||
|
@ -163,7 +163,6 @@ ClockWidget.prototype = {
|
||||
},
|
||||
|
||||
_updateCairo: function(time) {
|
||||
let global = Shell.Global.get();
|
||||
Shell.draw_clock(this.collapsedActor,
|
||||
time.getHours() % 12,
|
||||
time.getMinutes());
|
||||
|
@ -296,7 +296,7 @@ WidgetBox.prototype = {
|
||||
this.state == Widget.STATE_POPPING_OUT)) {
|
||||
// If moving into another actor within this._hbox, let the
|
||||
// event be propagated
|
||||
let into = Shell.get_event_related(event);
|
||||
let into = event.get_related();
|
||||
while (into) {
|
||||
if (into == this._hbox)
|
||||
return false;
|
||||
|
@ -1,9 +1,9 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const AltTab = imports.ui.altTab;
|
||||
const Main = imports.ui.main;
|
||||
@ -17,10 +17,8 @@ function WindowManager() {
|
||||
|
||||
WindowManager.prototype = {
|
||||
_init : function() {
|
||||
let me = this;
|
||||
let shellwm = global.window_manager;
|
||||
|
||||
this._global = Shell.Global.get();
|
||||
this._shellwm = this._global.window_manager;
|
||||
this._minimizing = [];
|
||||
this._maximizing = [];
|
||||
this._unmaximizing = [];
|
||||
@ -28,60 +26,20 @@ WindowManager.prototype = {
|
||||
this._destroying = [];
|
||||
|
||||
this._switchData = null;
|
||||
this._shellwm.connect('switch-workspace',
|
||||
function(o, from, to, direction) {
|
||||
let actors = me._shellwm.get_switch_workspace_actors();
|
||||
me._switchWorkspace(actors, from, to, direction);
|
||||
});
|
||||
this._shellwm.connect('kill-switch-workspace',
|
||||
function(o) {
|
||||
me._switchWorkspaceDone();
|
||||
});
|
||||
this._shellwm.connect('minimize',
|
||||
function(o, actor) {
|
||||
me._minimizeWindow(actor);
|
||||
});
|
||||
this._shellwm.connect('kill-minimize',
|
||||
function(o, actor) {
|
||||
me._minimizeWindowDone(actor);
|
||||
});
|
||||
this._shellwm.connect('maximize',
|
||||
function(o, actor, tx, ty, tw, th) {
|
||||
me._maximizeWindow(actor, tx, ty, tw, th);
|
||||
});
|
||||
this._shellwm.connect('kill-maximize',
|
||||
function(o, actor) {
|
||||
me._maximizeWindowDone(actor);
|
||||
});
|
||||
this._shellwm.connect('unmaximize',
|
||||
function(o, actor, tx, ty, tw, th) {
|
||||
me._unmaximizeWindow(actor, tx, ty, tw, th);
|
||||
});
|
||||
this._shellwm.connect('kill-unmaximize',
|
||||
function(o, actor) {
|
||||
me._unmaximizeWindowDone(actor);
|
||||
});
|
||||
this._shellwm.connect('map',
|
||||
function(o, actor) {
|
||||
me._mapWindow(actor);
|
||||
});
|
||||
this._shellwm.connect('kill-map',
|
||||
function(o, actor) {
|
||||
me._mapWindowDone(actor);
|
||||
});
|
||||
this._shellwm.connect('destroy',
|
||||
function(o, actor) {
|
||||
me._destroyWindow(actor);
|
||||
});
|
||||
this._shellwm.connect('kill-destroy',
|
||||
function(o, actor) {
|
||||
me._destroyWindowDone(actor);
|
||||
});
|
||||
shellwm.connect('switch-workspace', Lang.bind(this, this._switchWorkspace));
|
||||
shellwm.connect('kill-switch-workspace', Lang.bind(this, this._switchWorkspaceDone));
|
||||
shellwm.connect('minimize', Lang.bind(this, this._minimizeWindow));
|
||||
shellwm.connect('kill-minimize', Lang.bind(this, this._minimizeWindowDone));
|
||||
shellwm.connect('maximize', Lang.bind(this, this._maximizeWindow));
|
||||
shellwm.connect('kill-maximize', Lang.bind(this, this._maximizeWindowDone));
|
||||
shellwm.connect('unmaximize', Lang.bind(this, this._unmaximizeWindow));
|
||||
shellwm.connect('kill-unmaximize', Lang.bind(this, this._unmaximizeWindowDone));
|
||||
shellwm.connect('map', Lang.bind(this, this._mapWindow));
|
||||
shellwm.connect('kill-map', Lang.bind(this, this._mapWindowDone));
|
||||
shellwm.connect('destroy', Lang.bind(this, this._destroyWindow));
|
||||
shellwm.connect('kill-destroy', Lang.bind(this, this._destroyWindowDone));
|
||||
|
||||
this._shellwm.connect('begin-alt-tab',
|
||||
function(o, handler) {
|
||||
me._beginAltTab(handler);
|
||||
});
|
||||
shellwm.connect('begin-alt-tab', Lang.bind(this, this._beginAltTab));
|
||||
},
|
||||
|
||||
_shouldAnimate : function(actor) {
|
||||
@ -101,9 +59,9 @@ WindowManager.prototype = {
|
||||
return false;
|
||||
},
|
||||
|
||||
_minimizeWindow : function(actor) {
|
||||
_minimizeWindow : function(shellwm, actor) {
|
||||
if (!this._shouldAnimate(actor)) {
|
||||
this._shellwm.completed_minimize(actor);
|
||||
shellwm.completed_minimize(actor);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -121,49 +79,49 @@ WindowManager.prototype = {
|
||||
transition: "easeOutQuad",
|
||||
onComplete: this._minimizeWindowDone,
|
||||
onCompleteScope: this,
|
||||
onCompleteParams: [actor],
|
||||
onCompleteParams: [shellwm, actor],
|
||||
onOverwrite: this._minimizeWindowOverwritten,
|
||||
onOverwriteScope: this,
|
||||
onOverwriteParams: [actor]
|
||||
onOverwriteParams: [shellwm, actor]
|
||||
});
|
||||
},
|
||||
|
||||
_minimizeWindowDone : function(actor) {
|
||||
_minimizeWindowDone : function(shellwm, actor) {
|
||||
if (this._removeEffect(this._minimizing, actor)) {
|
||||
Tweener.removeTweens(actor);
|
||||
actor.set_scale(1.0, 1.0);
|
||||
actor.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_WEST);
|
||||
|
||||
this._shellwm.completed_minimize(actor);
|
||||
shellwm.completed_minimize(actor);
|
||||
}
|
||||
},
|
||||
|
||||
_minimizeWindowOverwritten : function(actor) {
|
||||
_minimizeWindowOverwritten : function(shellwm, actor) {
|
||||
if (this._removeEffect(this._minimizing, actor)) {
|
||||
this._shellwm.completed_minimize(actor);
|
||||
shellwm.completed_minimize(actor);
|
||||
}
|
||||
},
|
||||
|
||||
_maximizeWindow : function(actor, targetX, targetY, targetWidth, targetHeight) {
|
||||
this._shellwm.completed_maximize(actor);
|
||||
_maximizeWindow : function(shellwm, actor, targetX, targetY, targetWidth, targetHeight) {
|
||||
shellwm.completed_maximize(actor);
|
||||
},
|
||||
|
||||
_maximizeWindowDone : function(actor) {
|
||||
_maximizeWindowDone : function(shellwm, actor) {
|
||||
},
|
||||
|
||||
_maximizeWindowOverwrite : function(actor) {
|
||||
_maximizeWindowOverwrite : function(shellwm, actor) {
|
||||
},
|
||||
|
||||
_unmaximizeWindow : function(actor, targetX, targetY, targetWidth, targetHeight) {
|
||||
this._shellwm.completed_unmaximize(actor);
|
||||
_unmaximizeWindow : function(shellwm, actor, targetX, targetY, targetWidth, targetHeight) {
|
||||
shellwm.completed_unmaximize(actor);
|
||||
},
|
||||
|
||||
_unmaximizeWindowDone : function(actor) {
|
||||
_unmaximizeWindowDone : function(shellwm, actor) {
|
||||
},
|
||||
|
||||
_mapWindow : function(actor) {
|
||||
_mapWindow : function(shellwm, actor) {
|
||||
if (!this._shouldAnimate(actor)) {
|
||||
this._shellwm.completed_map(actor);
|
||||
shellwm.completed_map(actor);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -180,31 +138,31 @@ WindowManager.prototype = {
|
||||
transition: "easeOutQuad",
|
||||
onComplete: this._mapWindowDone,
|
||||
onCompleteScope: this,
|
||||
onCompleteParams: [actor],
|
||||
onCompleteParams: [shellwm, actor],
|
||||
onOverwrite: this._mapWindowOverwrite,
|
||||
onOverwriteScope: this,
|
||||
onOverwriteParams: [actor]
|
||||
onOverwriteParams: [shellwm, actor]
|
||||
});
|
||||
},
|
||||
|
||||
_mapWindowDone : function(actor) {
|
||||
_mapWindowDone : function(shellwm, actor) {
|
||||
if (this._removeEffect(this._mapping, actor)) {
|
||||
Tweener.removeTweens(actor);
|
||||
actor.set_scale(1.0, 1.0);
|
||||
actor.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_WEST);
|
||||
this._shellwm.completed_map(actor);
|
||||
shellwm.completed_map(actor);
|
||||
}
|
||||
},
|
||||
|
||||
_mapWindowOverwrite : function(actor) {
|
||||
_mapWindowOverwrite : function(shellwm, actor) {
|
||||
if (this._removeEffect(this._mapping, actor)) {
|
||||
this._shellwm.completed_map(actor);
|
||||
shellwm.completed_map(actor);
|
||||
}
|
||||
},
|
||||
|
||||
_destroyWindow : function(actor) {
|
||||
_destroyWindow : function(shellwm, actor) {
|
||||
if (!this._shouldAnimate(actor)) {
|
||||
this._shellwm.completed_destroy(actor);
|
||||
shellwm.completed_destroy(actor);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -219,33 +177,35 @@ WindowManager.prototype = {
|
||||
transition: "easeOutQuad",
|
||||
onComplete: this._destroyWindowDone,
|
||||
onCompleteScope: this,
|
||||
onCompleteParams: [actor],
|
||||
onCompleteParams: [shellwm, actor],
|
||||
onOverwrite: this._destroyWindowOverwrite,
|
||||
onOverwriteScope: this,
|
||||
onOverwriteParams: [actor]
|
||||
onOverwriteParams: [shellwm, actor]
|
||||
});
|
||||
},
|
||||
|
||||
_destroyWindowDone : function(actor) {
|
||||
_destroyWindowDone : function(shellwm, actor) {
|
||||
if (this._removeEffect(this._destroying, actor)) {
|
||||
this._shellwm.completed_destroy(actor);
|
||||
shellwm.completed_destroy(actor);
|
||||
Tweener.removeTweens(actor);
|
||||
actor.set_scale(1.0, 1.0);
|
||||
}
|
||||
},
|
||||
|
||||
_destroyWindowOverwrite : function(actor) {
|
||||
_destroyWindowOverwrite : function(shellwm, actor) {
|
||||
if (this._removeEffect(this._destroying, actor)) {
|
||||
this._shellwm.completed_destroy(actor);
|
||||
shellwm.completed_destroy(actor);
|
||||
}
|
||||
},
|
||||
|
||||
_switchWorkspace : function(windows, from, to, direction) {
|
||||
_switchWorkspace : function(shellwm, from, to, direction) {
|
||||
if (!this._shouldAnimate()) {
|
||||
this._shellwm.completed_switch_workspace();
|
||||
shellwm.completed_switch_workspace();
|
||||
return;
|
||||
}
|
||||
|
||||
let windows = shellwm.get_switch_workspace_actors();
|
||||
|
||||
/* @direction is the direction that the "camera" moves, so the
|
||||
* screen contents have to move one screen's worth in the
|
||||
* opposite direction.
|
||||
@ -255,20 +215,20 @@ WindowManager.prototype = {
|
||||
if (direction == Meta.MotionDirection.UP ||
|
||||
direction == Meta.MotionDirection.UP_LEFT ||
|
||||
direction == Meta.MotionDirection.UP_RIGHT)
|
||||
yDest = this._global.screen_height;
|
||||
yDest = global.screen_height;
|
||||
else if (direction == Meta.MotionDirection.DOWN ||
|
||||
direction == Meta.MotionDirection.DOWN_LEFT ||
|
||||
direction == Meta.MotionDirection.DOWN_RIGHT)
|
||||
yDest = -this._global.screen_height;
|
||||
yDest = -global.screen_height;
|
||||
|
||||
if (direction == Meta.MotionDirection.LEFT ||
|
||||
direction == Meta.MotionDirection.UP_LEFT ||
|
||||
direction == Meta.MotionDirection.DOWN_LEFT)
|
||||
xDest = this._global.screen_width;
|
||||
xDest = global.screen_width;
|
||||
else if (direction == Meta.MotionDirection.RIGHT ||
|
||||
direction == Meta.MotionDirection.UP_RIGHT ||
|
||||
direction == Meta.MotionDirection.DOWN_RIGHT)
|
||||
xDest = -this._global.screen_width;
|
||||
xDest = -global.screen_width;
|
||||
|
||||
let switchData = {};
|
||||
this._switchData = switchData;
|
||||
@ -276,7 +236,7 @@ WindowManager.prototype = {
|
||||
switchData.outGroup = new Clutter.Group();
|
||||
switchData.windows = [];
|
||||
|
||||
let wgroup = this._global.window_group;
|
||||
let wgroup = global.window_group;
|
||||
wgroup.add_actor(switchData.inGroup);
|
||||
wgroup.add_actor(switchData.outGroup);
|
||||
|
||||
@ -307,7 +267,8 @@ WindowManager.prototype = {
|
||||
time: WINDOW_ANIMATION_TIME,
|
||||
transition: "easeOutQuad",
|
||||
onComplete: this._switchWorkspaceDone,
|
||||
onCompleteScope: this
|
||||
onCompleteScope: this,
|
||||
onCompleteParams: [shellwm]
|
||||
});
|
||||
Tweener.addTween(switchData.inGroup,
|
||||
{ x: 0,
|
||||
@ -317,7 +278,7 @@ WindowManager.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
_switchWorkspaceDone : function() {
|
||||
_switchWorkspaceDone : function(shellwm) {
|
||||
let switchData = this._switchData;
|
||||
if (!switchData)
|
||||
return;
|
||||
@ -336,10 +297,10 @@ WindowManager.prototype = {
|
||||
switchData.inGroup.destroy();
|
||||
switchData.outGroup.destroy();
|
||||
|
||||
this._shellwm.completed_switch_workspace();
|
||||
shellwm.completed_switch_workspace();
|
||||
},
|
||||
|
||||
_beginAltTab : function(handler) {
|
||||
_beginAltTab : function(shellwm, handler) {
|
||||
let popup = new AltTab.AltTabPopup();
|
||||
|
||||
handler.connect('window-added', function(handler, window) { popup.addWindow(window); });
|
||||
|
@ -25,6 +25,12 @@ const WINDOWCLONE_TITLE_COLOR = new Clutter.Color();
|
||||
WINDOWCLONE_TITLE_COLOR.from_pixel(0xffffffff);
|
||||
const FRAME_COLOR = new Clutter.Color();
|
||||
FRAME_COLOR.from_pixel(0xffffffff);
|
||||
const LIGHTBOX_COLOR = new Clutter.Color();
|
||||
LIGHTBOX_COLOR.from_pixel(0x00000044);
|
||||
|
||||
const SCROLL_SCALE_AMOUNT = 100 / 5;
|
||||
|
||||
const ZOOM_OVERLAY_FADE_TIME = 0.15;
|
||||
|
||||
// Define a layout scheme for small window counts. For larger
|
||||
// counts we fall back to an algorithm. We need more schemes here
|
||||
@ -40,13 +46,53 @@ const POSITIONS = {
|
||||
5: [[0.165, 0.25, 0.32], [0.495, 0.25, 0.32], [0.825, 0.25, 0.32], [0.25, 0.75, 0.32], [0.75, 0.75, 0.32]]
|
||||
};
|
||||
|
||||
|
||||
function _interpolate(start, end, step) {
|
||||
return start + (end - start) * step;
|
||||
}
|
||||
|
||||
function _clamp(value, min, max) {
|
||||
return Math.max(min, Math.min(max, value));
|
||||
}
|
||||
|
||||
// Spacing between workspaces. At the moment, the same spacing is used
|
||||
// in both zoomed-in and zoomed-out views; this is slightly
|
||||
// metaphor-breaking, but the alternatives are also weird.
|
||||
const GRID_SPACING = 15;
|
||||
const FRAME_SIZE = GRID_SPACING / 3;
|
||||
|
||||
let buttonSize = false;
|
||||
function ScaledPoint(x, y, scaleX, scaleY) {
|
||||
[this.x, this.y, this.scaleX, this.scaleY] = arguments;
|
||||
}
|
||||
|
||||
ScaledPoint.prototype = {
|
||||
getPosition : function() {
|
||||
return [this.x, this.y];
|
||||
},
|
||||
|
||||
getScale : function() {
|
||||
return [this.scaleX, this.scaleY];
|
||||
},
|
||||
|
||||
setPosition : function(x, y) {
|
||||
[this.x, this.y] = arguments;
|
||||
},
|
||||
|
||||
setScale : function(scaleX, scaleY) {
|
||||
[this.scaleX, this.scaleY] = arguments;
|
||||
},
|
||||
|
||||
interpPosition : function(other, step) {
|
||||
return [_interpolate(this.x, other.x, step),
|
||||
_interpolate(this.y, other.y, step)];
|
||||
},
|
||||
|
||||
interpScale : function(other, step) {
|
||||
return [_interpolate(this.scaleX, other.scaleX, step),
|
||||
_interpolate(this.scaleY, other.scaleY, step)];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function WindowClone(realWindow) {
|
||||
this._init(realWindow);
|
||||
@ -61,12 +107,18 @@ WindowClone.prototype = {
|
||||
this.actor._delegate = this;
|
||||
this.realWindow = realWindow;
|
||||
this.metaWindow = realWindow.meta_window;
|
||||
this.metaWindow._delegate = this;
|
||||
this.origX = realWindow.x;
|
||||
this.origY = realWindow.y;
|
||||
|
||||
this._title = null;
|
||||
|
||||
this.actor.connect('button-release-event',
|
||||
Lang.bind(this, this._onButtonRelease));
|
||||
|
||||
this.actor.connect('scroll-event',
|
||||
Lang.bind(this, this._onScroll));
|
||||
|
||||
this.actor.connect('enter-event',
|
||||
Lang.bind(this, this._onEnter));
|
||||
this.actor.connect('leave-event',
|
||||
@ -79,6 +131,18 @@ WindowClone.prototype = {
|
||||
this._inDrag = false;
|
||||
},
|
||||
|
||||
setVisibleWithChrome: function(visible) {
|
||||
if (visible) {
|
||||
this.actor.show();
|
||||
if (this._title)
|
||||
this._title.show();
|
||||
} else {
|
||||
this.actor.hide();
|
||||
if (this._title)
|
||||
this._title.hide();
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
this.actor.destroy();
|
||||
if (this._title)
|
||||
@ -104,12 +168,103 @@ WindowClone.prototype = {
|
||||
return;
|
||||
|
||||
this._havePointer = false;
|
||||
|
||||
if (Tweener.isTweening(this.actor))
|
||||
return;
|
||||
|
||||
actor.raise(this.stackAbove);
|
||||
this._updateTitle();
|
||||
|
||||
if (this._zoomStep)
|
||||
this._zoomEnd();
|
||||
},
|
||||
|
||||
_onScroll : function (actor, event) {
|
||||
let direction = event.get_scroll_direction();
|
||||
if (direction == Clutter.ScrollDirection.UP) {
|
||||
if (this._zoomStep == undefined)
|
||||
this._zoomStart();
|
||||
if (this._zoomStep < 100) {
|
||||
this._zoomStep += SCROLL_SCALE_AMOUNT;
|
||||
this._zoomUpdate();
|
||||
}
|
||||
} else if (direction == Clutter.ScrollDirection.DOWN) {
|
||||
if (this._zoomStep > 0) {
|
||||
this._zoomStep -= SCROLL_SCALE_AMOUNT;
|
||||
this._zoomStep = Math.max(0, this._zoomStep);
|
||||
this._zoomUpdate();
|
||||
}
|
||||
if (this._zoomStep <= 0.0)
|
||||
this._zoomEnd();
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
_zoomUpdate : function () {
|
||||
[this.actor.x, this.actor.y] = this._zoomGlobalOrig.interpPosition(this._zoomTarget, this._zoomStep / 100);
|
||||
[this.actor.scale_x, this.actor.scale_y] = this._zoomGlobalOrig.interpScale(this._zoomTarget, this._zoomStep / 100);
|
||||
|
||||
let [width, height] = this.actor.get_transformed_size();
|
||||
|
||||
this.actor.x = _clamp(this.actor.x, 0, global.screen_width - width);
|
||||
this.actor.y = _clamp(this.actor.y, Panel.PANEL_HEIGHT, global.screen_height - height);
|
||||
},
|
||||
|
||||
_zoomStart : function () {
|
||||
this._zoomOverlay = new Clutter.Rectangle({ reactive: true,
|
||||
color: LIGHTBOX_COLOR,
|
||||
border_width: 0,
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: global.screen_width,
|
||||
height: global.screen_height,
|
||||
opacity: 0 });
|
||||
this._zoomOverlay.show();
|
||||
global.stage.add_actor(this._zoomOverlay);
|
||||
Tweener.addTween(this._zoomOverlay,
|
||||
{ opacity: 255,
|
||||
time: ZOOM_OVERLAY_FADE_TIME,
|
||||
transition: "easeOutQuad"
|
||||
});
|
||||
|
||||
this._zoomLocalOrig = new ScaledPoint(this.actor.x, this.actor.y, this.actor.scale_x, this.actor.scale_y);
|
||||
this._zoomGlobalOrig = new ScaledPoint();
|
||||
let parent = this._origParent = this.actor.get_parent();
|
||||
[width, height] = this.actor.get_transformed_size();
|
||||
this._zoomGlobalOrig.setPosition.apply(this._zoomGlobalOrig, this.actor.get_transformed_position());
|
||||
this._zoomGlobalOrig.setScale(width / this.actor.width, height / this.actor.height);
|
||||
|
||||
this._zoomOverlay.raise_top();
|
||||
this._zoomOverlay.show();
|
||||
|
||||
this.actor.reparent(global.stage);
|
||||
|
||||
[this.actor.x, this.actor.y] = this._zoomGlobalOrig.getPosition();
|
||||
[this.actor.scale_x, this.actor.scale_y] = this._zoomGlobalOrig.getScale();
|
||||
|
||||
this.actor.raise_top();
|
||||
|
||||
this._zoomTarget = new ScaledPoint(0, 0, 1.0, 1.0);
|
||||
this._zoomTarget.setPosition(this.actor.x - (this.actor.width - width) / 2, this.actor.y - (this.actor.height - height) / 2);
|
||||
this._zoomStep = 0;
|
||||
|
||||
this._hideEventId = Main.overview.connect('hiding', Lang.bind(this, function () { this._zoomEnd(); }));
|
||||
this._zoomUpdate();
|
||||
},
|
||||
|
||||
_zoomEnd : function () {
|
||||
this.actor.reparent(this._origParent);
|
||||
|
||||
[this.actor.x, this.actor.y] = this._zoomLocalOrig.getPosition();
|
||||
[this.actor.scale_x, this.actor.scale_y] = this._zoomLocalOrig.getScale();
|
||||
|
||||
this._adjustTitle();
|
||||
|
||||
this._zoomOverlay.destroy();
|
||||
Main.overview.disconnect(this._hideEventId);
|
||||
|
||||
this._zoomLocalPosition = undefined;
|
||||
this._zoomLocalScale = undefined;
|
||||
this._zoomGlobalPosition = undefined;
|
||||
this._zoomGlobalScale = undefined;
|
||||
this._zoomTargetPosition = undefined;
|
||||
this._zoomStep = undefined;
|
||||
this._zoomOverlay = undefined;
|
||||
},
|
||||
|
||||
_onButtonRelease : function (actor, event) {
|
||||
@ -231,7 +386,6 @@ DesktopClone.prototype = {
|
||||
this.actor = new Clutter.Clone({ source: window.get_texture(),
|
||||
reactive: true });
|
||||
} else {
|
||||
let global = Shell.Global.get();
|
||||
this.actor = new Clutter.Rectangle({ color: global.stage.color,
|
||||
reactive: true,
|
||||
width: global.screen_width,
|
||||
@ -262,9 +416,6 @@ function Workspace(workspaceNum, parentActor) {
|
||||
|
||||
Workspace.prototype = {
|
||||
_init : function(workspaceNum, parentActor) {
|
||||
let me = this;
|
||||
let global = Shell.Global.get();
|
||||
|
||||
this.workspaceNum = workspaceNum;
|
||||
this._metaWorkspace = global.screen.get_workspace_by_index(workspaceNum);
|
||||
|
||||
@ -280,6 +431,14 @@ Workspace.prototype = {
|
||||
this.actor.height = global.screen_height;
|
||||
this.scale = 1.0;
|
||||
|
||||
this._lightbox = new Clutter.Rectangle({ color: LIGHTBOX_COLOR });
|
||||
this.actor.connect('notify::allocation', Lang.bind(this, function () {
|
||||
let [width, height] = this.actor.get_size();
|
||||
this._lightbox.set_size(width, height);
|
||||
}));
|
||||
this.actor.add_actor(this._lightbox);
|
||||
this._lightbox.hide();
|
||||
|
||||
let windows = global.get_windows().filter(this._isMyWindow, this);
|
||||
|
||||
// Find the desktop window
|
||||
@ -311,6 +470,9 @@ Workspace.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
// A filter for what windows we display
|
||||
this._showOnlyWindows = null;
|
||||
|
||||
// Track window changes
|
||||
this._windowAddedId = this._metaWorkspace.connect('window-added',
|
||||
Lang.bind(this, this._windowAdded));
|
||||
@ -326,7 +488,6 @@ Workspace.prototype = {
|
||||
},
|
||||
|
||||
updateRemovable : function() {
|
||||
let global = Shell.Global.get();
|
||||
let removable = (this._windows.length == 1 /* just desktop */ &&
|
||||
this.workspaceNum != 0 &&
|
||||
this.workspaceNum == global.screen.n_workspaces - 1);
|
||||
@ -335,8 +496,8 @@ Workspace.prototype = {
|
||||
if (this._removeButton)
|
||||
return;
|
||||
|
||||
this._removeButton = new Clutter.Texture({ width: buttonSize,
|
||||
height: buttonSize,
|
||||
this._removeButton = new Clutter.Texture({ width: Overview.addRemoveButtonSize,
|
||||
height: Overview.addRemoveButtonSize,
|
||||
reactive: true
|
||||
});
|
||||
this._removeButton.set_from_file(global.imagedir + "remove-workspace.svg");
|
||||
@ -381,11 +542,60 @@ Workspace.prototype = {
|
||||
return -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* lookupCloneForMetaWindow:
|
||||
* @metaWindow: A #MetaWindow
|
||||
*
|
||||
* Given a #MetaWindow instance, find the WindowClone object
|
||||
* which represents it in the workspaces display.
|
||||
*/
|
||||
lookupCloneForMetaWindow: function (metaWindow) {
|
||||
let index = this._lookupIndex (metaWindow);
|
||||
return index < 0 ? null : this._windows[index];
|
||||
},
|
||||
|
||||
containsMetaWindow: function (metaWindow) {
|
||||
return this._lookupIndex(metaWindow) >= 0;
|
||||
},
|
||||
|
||||
setShowOnlyWindows: function(showOnlyWindows, reposition) {
|
||||
this._showOnlyWindows = showOnlyWindows;
|
||||
this._resetCloneVisibility();
|
||||
if (reposition)
|
||||
this.positionWindows(false);
|
||||
},
|
||||
|
||||
/**
|
||||
* setLightboxMode:
|
||||
* @showLightbox: If true, dim background and allow highlighting a specific window
|
||||
*
|
||||
* This function also resets the highlighted window state.
|
||||
*/
|
||||
setLightboxMode: function (showLightbox) {
|
||||
if (showLightbox) {
|
||||
this.setHighlightWindow(null);
|
||||
this._lightbox.show();
|
||||
} else {
|
||||
this._lightbox.hide();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* setHighlightWindow:
|
||||
* @metaWindow: A #MetaWindow
|
||||
*
|
||||
* Draw the user's attention to the given window @metaWindow.
|
||||
*/
|
||||
setHighlightWindow: function (metaWindow) {
|
||||
for (let i = 0; i < this._windows.length; i++) {
|
||||
this._windows[i].actor.lower(this._lightbox);
|
||||
}
|
||||
if (metaWindow != null) {
|
||||
let clone = this.lookupCloneForMetaWindow(metaWindow);
|
||||
clone.actor.raise(this._lightbox);
|
||||
}
|
||||
},
|
||||
|
||||
_adjustRemoveButton : function() {
|
||||
this._removeButton.set_scale(1.0 / this.actor.scale_x,
|
||||
1.0 / this.actor.scale_y);
|
||||
@ -402,7 +612,6 @@ Workspace.prototype = {
|
||||
|
||||
// Mark the workspace selected/not-selected
|
||||
setSelected : function(selected) {
|
||||
let global = Shell.Global.get();
|
||||
// Don't draw a frame if we only have one workspace
|
||||
if (selected && global.screen.n_workspaces > 1) {
|
||||
if (this._frame)
|
||||
@ -434,18 +643,51 @@ Workspace.prototype = {
|
||||
this._desktop.actor.height + 2 * FRAME_SIZE / this.actor.scale_y);
|
||||
},
|
||||
|
||||
// Reposition all windows in their zoomed-to-Overview position. if workspaceZooming
|
||||
// is true, then the workspace is moving at the same time and we need to take
|
||||
// that into account
|
||||
positionWindows : function(workspaceZooming) {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
_resetCloneVisibility: function () {
|
||||
for (let i = 1; i < this._windows.length; i++) {
|
||||
let clone = this._windows[i];
|
||||
let icon = this._windowIcons[i];
|
||||
clone.stackAbove = this._windows[i - 1].actor;
|
||||
|
||||
let [xCenter, yCenter, fraction] = this._computeWindowPosition(i);
|
||||
if (this._showOnlyWindows != null && !(clone.metaWindow in this._showOnlyWindows)) {
|
||||
clone.setVisibleWithChrome(false);
|
||||
icon.hide();
|
||||
} else {
|
||||
clone.setVisibleWithChrome(true);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* positionWindows:
|
||||
* @workspaceZooming: If true, then the workspace is moving at the same time and we need to take that into account.
|
||||
*/
|
||||
positionWindows : function(workspaceZooming) {
|
||||
let totalVisible = 0;
|
||||
|
||||
for (let i = 1; i < this._windows.length; i++) {
|
||||
let clone = this._windows[i];
|
||||
|
||||
if (this._showOnlyWindows != null && !(clone.metaWindow in this._showOnlyWindows))
|
||||
continue;
|
||||
|
||||
totalVisible += 1;
|
||||
}
|
||||
|
||||
let previousWindow = this._windows[0];
|
||||
let visibleIndex = 0;
|
||||
for (let i = 1; i < this._windows.length; i++) {
|
||||
let clone = this._windows[i];
|
||||
let icon = this._windowIcons[i];
|
||||
|
||||
if (this._showOnlyWindows != null && !(clone.metaWindow in this._showOnlyWindows))
|
||||
continue;
|
||||
|
||||
clone.stackAbove = previousWindow.actor;
|
||||
previousWindow = clone;
|
||||
|
||||
visibleIndex += 1;
|
||||
|
||||
let [xCenter, yCenter, fraction] = this._computeWindowPosition(visibleIndex, totalVisible);
|
||||
xCenter = xCenter * global.screen_width;
|
||||
yCenter = yCenter * global.screen_height;
|
||||
|
||||
@ -508,6 +750,8 @@ Workspace.prototype = {
|
||||
for (let i = 1; i < this._windows.length; i++) {
|
||||
let clone = this._windows[i];
|
||||
let icon = this._windowIcons[i];
|
||||
if (this._showOnlyWindows != null && !(clone.metaWindow in this._showOnlyWindows))
|
||||
continue;
|
||||
this._fadeInWindowIcon(clone, icon);
|
||||
}
|
||||
},
|
||||
@ -520,7 +764,6 @@ Workspace.prototype = {
|
||||
},
|
||||
|
||||
_windowRemoved : function(metaWorkspace, metaWin) {
|
||||
let global = Shell.Global.get();
|
||||
let win = metaWin.get_compositor_private();
|
||||
|
||||
// find the position of the window in our list
|
||||
@ -672,8 +915,6 @@ Workspace.prototype = {
|
||||
|
||||
// Animates the addition of a new (empty) workspace
|
||||
slideIn : function(oldScale) {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
if (this.gridCol > this.gridRow) {
|
||||
this.actor.set_position(global.screen_width, this.gridY);
|
||||
this.actor.set_scale(oldScale, oldScale);
|
||||
@ -695,7 +936,6 @@ Workspace.prototype = {
|
||||
|
||||
// Animates the removal of a workspace
|
||||
slideOut : function(onComplete) {
|
||||
let global = Shell.Global.get();
|
||||
let destX = this.actor.x, destY = this.actor.y;
|
||||
|
||||
this._hideAllIcons();
|
||||
@ -722,8 +962,6 @@ Workspace.prototype = {
|
||||
},
|
||||
|
||||
destroy : function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
Tweener.removeTweens(this.actor);
|
||||
this.actor.destroy();
|
||||
this.actor = null;
|
||||
@ -794,10 +1032,10 @@ Workspace.prototype = {
|
||||
return clone;
|
||||
},
|
||||
|
||||
_computeWindowPosition : function(index) {
|
||||
_computeWindowPosition : function(index, totalWindows) {
|
||||
// ignore this._windows[0], which is the desktop
|
||||
let windowIndex = index - 1;
|
||||
let numberOfWindows = this._windows.length - 1;
|
||||
let numberOfWindows = totalWindows;
|
||||
|
||||
if (numberOfWindows in POSITIONS)
|
||||
return POSITIONS[numberOfWindows][windowIndex];
|
||||
@ -820,7 +1058,6 @@ Workspace.prototype = {
|
||||
},
|
||||
|
||||
_removeSelf : function(actor, event) {
|
||||
let global = Shell.Global.get();
|
||||
let screen = global.screen;
|
||||
let workspace = screen.get_workspace_by_index(this.workspaceNum);
|
||||
|
||||
@ -830,8 +1067,6 @@ Workspace.prototype = {
|
||||
|
||||
// Draggable target interface
|
||||
acceptDrop : function(source, actor, x, y, time) {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
if (source instanceof WindowClone) {
|
||||
let win = source.realWindow;
|
||||
if (this._isMyWindow(win))
|
||||
@ -862,25 +1097,25 @@ Workspace.prototype = {
|
||||
|
||||
Signals.addSignalMethods(Workspace.prototype);
|
||||
|
||||
function Workspaces(width, height, x, y, addButtonSize, addButtonX, addButtonY) {
|
||||
this._init(width, height, x, y, addButtonSize, addButtonX, addButtonY);
|
||||
function Workspaces(width, height, x, y) {
|
||||
this._init(width, height, x, y);
|
||||
}
|
||||
|
||||
Workspaces.prototype = {
|
||||
_init : function(width, height, x, y, addButtonSize, addButtonX, addButtonY) {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
_init : function(width, height, x, y) {
|
||||
this.actor = new Clutter.Group();
|
||||
|
||||
let screenHeight = global.screen_height;
|
||||
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
|
||||
this._windowSelectionAppId = null;
|
||||
|
||||
this._workspaces = [];
|
||||
|
||||
|
||||
this._highlightWindow = null;
|
||||
|
||||
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
||||
let activeWorkspace;
|
||||
|
||||
@ -893,17 +1128,7 @@ Workspaces.prototype = {
|
||||
}
|
||||
}
|
||||
activeWorkspace.actor.raise_top();
|
||||
this._positionWorkspaces(global);
|
||||
|
||||
// Save the button size as a global variable so we can us it to create
|
||||
// matching button sizes for workspace remove buttons.
|
||||
buttonSize = addButtonSize;
|
||||
|
||||
// Create (+) button
|
||||
this.addButton = new AddWorkspaceButton(addButtonSize, addButtonX, addButtonY, Lang.bind(this, this._addWorkspaceAcceptDrop));
|
||||
this.addButton.actor.connect('button-release-event', Lang.bind(this, this._appendNewWorkspace));
|
||||
this.actor.add_actor(this.addButton.actor);
|
||||
this.addButton.actor.lower_bottom();
|
||||
this._positionWorkspaces();
|
||||
|
||||
let lastWorkspace = this._workspaces[this._workspaces.length - 1];
|
||||
lastWorkspace.updateRemovable(true);
|
||||
@ -927,6 +1152,14 @@ Workspaces.prototype = {
|
||||
Lang.bind(this, this._activeWorkspaceChanged));
|
||||
},
|
||||
|
||||
_lookupWorkspaceForMetaWindow: function (metaWindow) {
|
||||
for (let i = 0; i < this._workspaces.length; i++) {
|
||||
if (this._workspaces[i].containsMetaWindow(metaWindow))
|
||||
return this._workspaces[i];
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
_lookupCloneForMetaWindow: function (metaWindow) {
|
||||
for (let i = 0; i < this._workspaces.length; i++) {
|
||||
let clone = this._workspaces[i].lookupCloneForMetaWindow(metaWindow);
|
||||
@ -936,9 +1169,64 @@ Workspaces.prototype = {
|
||||
return null;
|
||||
},
|
||||
|
||||
// Should only be called from active Overview context
|
||||
activateWindowFromOverview: function (metaWindow, time) {
|
||||
let global = Shell.Global.get();
|
||||
setHighlightWindow: function (metaWindow) {
|
||||
// Looping over all workspaces is easier than keeping track of the last
|
||||
// highlighted window while trying to handle the window or workspace possibly
|
||||
// going away.
|
||||
for (let i = 0; i < this._workspaces.length; i++) {
|
||||
this._workspaces[i].setHighlightWindow(null);
|
||||
}
|
||||
if (metaWindow != null) {
|
||||
let workspace = this._lookupWorkspaceForMetaWindow(metaWindow);
|
||||
workspace.setHighlightWindow(metaWindow);
|
||||
}
|
||||
},
|
||||
|
||||
_clearApplicationWindowSelection: function(reposition) {
|
||||
if (this._windowSelectionAppId == null)
|
||||
return;
|
||||
this._windowSelectionAppId = null;
|
||||
|
||||
for (let i = 0; i < this._workspaces.length; i++) {
|
||||
this._workspaces[i].setLightboxMode(false);
|
||||
this._workspaces[i].setShowOnlyWindows(null, reposition);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* setApplicationWindowSelection:
|
||||
* @appid: Application identifier string
|
||||
*
|
||||
* Enter a mode which shows only the windows owned by the
|
||||
* given application, and allow highlighting of a specific
|
||||
* window with setHighlightWindow().
|
||||
*/
|
||||
setApplicationWindowSelection: function (appId) {
|
||||
if (appId == null) {
|
||||
this._clearApplicationWindowSelection(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (appId == this._windowSelectionAppId)
|
||||
return;
|
||||
|
||||
this._windowSelectionAppId = appId;
|
||||
|
||||
let appSys = Shell.AppMonitor.get_default();
|
||||
|
||||
let showOnlyWindows = {};
|
||||
let windows = appSys.get_windows_for_app(appId);
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
showOnlyWindows[windows[i]] = 1;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this._workspaces.length; i++) {
|
||||
this._workspaces[i].setLightboxMode(true);
|
||||
this._workspaces[i].setShowOnlyWindows(showOnlyWindows, true);
|
||||
}
|
||||
},
|
||||
|
||||
_activateWindowInternal: function (metaWindow, time) {
|
||||
let activeWorkspaceNum = global.screen.get_active_workspace_index();
|
||||
let windowWorkspaceNum = metaWindow.get_workspace().index();
|
||||
|
||||
@ -953,12 +1241,27 @@ Workspaces.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* activateWindowFromOverview:
|
||||
* @metaWindow: A #MetaWindow
|
||||
* @time: Integer even timestamp
|
||||
*
|
||||
* This function exits the overview, switching to the given @metaWindow.
|
||||
* If an application filter is in effect, it will be cleared.
|
||||
*/
|
||||
activateWindowFromOverview: function (metaWindow, time) {
|
||||
if (this._windowSelectionAppId != null) {
|
||||
this._clearApplicationWindowSelection(false);
|
||||
}
|
||||
this._activateWindowInternal(metaWindow, time);
|
||||
Main.overview.hide();
|
||||
},
|
||||
|
||||
hide : function() {
|
||||
let global = Shell.Global.get();
|
||||
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
||||
let activeWorkspace = this._workspaces[activeWorkspaceIndex];
|
||||
|
||||
this._positionWorkspaces(global);
|
||||
this._positionWorkspaces();
|
||||
activeWorkspace.actor.raise_top();
|
||||
|
||||
for (let w = 0; w < this._workspaces.length; w++)
|
||||
@ -966,8 +1269,6 @@ Workspaces.prototype = {
|
||||
},
|
||||
|
||||
destroy : function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
for (let w = 0; w < this._workspaces.length; w++)
|
||||
this._workspaces[w].destroy();
|
||||
this._workspaces = [];
|
||||
@ -985,7 +1286,6 @@ Workspaces.prototype = {
|
||||
|
||||
// Get the grid position of the active workspace.
|
||||
getActiveWorkspacePosition : function() {
|
||||
let global = Shell.Global.get();
|
||||
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
||||
let activeWorkspace = this._workspaces[activeWorkspaceIndex];
|
||||
|
||||
@ -1002,7 +1302,7 @@ Workspaces.prototype = {
|
||||
// first row.)
|
||||
//
|
||||
// FIXME: need to make the metacity internal layout agree with this!
|
||||
_positionWorkspaces : function(global) {
|
||||
_positionWorkspaces : function() {
|
||||
let gridWidth = Math.ceil(Math.sqrt(this._workspaces.length));
|
||||
let gridHeight = Math.ceil(this._workspaces.length / gridWidth);
|
||||
|
||||
@ -1040,8 +1340,6 @@ Workspaces.prototype = {
|
||||
},
|
||||
|
||||
_workspacesChanged : function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
let oldNumWorkspaces = this._workspaces.length;
|
||||
let newNumWorkspaces = global.screen.n_workspaces;
|
||||
|
||||
@ -1074,7 +1372,7 @@ Workspaces.prototype = {
|
||||
newLastWorkspace.updateRemovable();
|
||||
|
||||
// Figure out the new layout
|
||||
this._positionWorkspaces(global);
|
||||
this._positionWorkspaces();
|
||||
let newScale = this._workspaces[0].scale;
|
||||
let newGridWidth = Math.ceil(Math.sqrt(newNumWorkspaces));
|
||||
let newGridHeight = Math.ceil(newNumWorkspaces / newGridWidth);
|
||||
@ -1125,42 +1423,13 @@ Workspaces.prototype = {
|
||||
this.actor.add_actor(workspace.actor);
|
||||
},
|
||||
|
||||
_appendNewWorkspace : function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
global.screen.append_new_workspace(false, global.screen.get_display().get_current_time());
|
||||
},
|
||||
|
||||
// Creates a new workspace and drops the dropActor there
|
||||
_addWorkspaceAcceptDrop : function(source, dropActor, x, y, time) {
|
||||
this._appendNewWorkspace();
|
||||
// Handles a drop onto the (+) button; assumes the new workspace
|
||||
// has already been added
|
||||
acceptNewWorkspaceDrop : function(source, dropActor, x, y, time) {
|
||||
return this._workspaces[this._workspaces.length - 1].acceptDrop(source, dropActor, x, y, time);
|
||||
}
|
||||
};
|
||||
|
||||
function AddWorkspaceButton(buttonSize, buttonX, buttonY, acceptDropCallback) {
|
||||
this._init(buttonSize, buttonX, buttonY, acceptDropCallback);
|
||||
}
|
||||
|
||||
AddWorkspaceButton.prototype = {
|
||||
_init : function(buttonSize, buttonX, buttonY, acceptDropCallback) {
|
||||
this.actor = new Clutter.Texture({ x: buttonX,
|
||||
y: buttonY,
|
||||
width: buttonSize,
|
||||
height: buttonSize,
|
||||
reactive: true });
|
||||
this._acceptDropCallback = acceptDropCallback;
|
||||
let global = Shell.Global.get();
|
||||
this.actor._delegate = this;
|
||||
this.actor.set_from_file(global.imagedir + 'add-workspace.svg');
|
||||
},
|
||||
|
||||
// Draggable target interface
|
||||
acceptDrop : function(source, actor, x, y, time) {
|
||||
return this._acceptDropCallback(source, actor, x, y, time);
|
||||
}
|
||||
};
|
||||
|
||||
// Create a SpecialPropertyModifier to let us move windows in a
|
||||
// straight line on the screen even though their containing workspace
|
||||
// is also moving.
|
||||
|
@ -2,6 +2,7 @@ ca
|
||||
cs
|
||||
da
|
||||
de
|
||||
en_GB
|
||||
es
|
||||
fr
|
||||
ga
|
||||
|
184
po/en_GB.po
Normal file
184
po/en_GB.po
Normal file
@ -0,0 +1,184 @@
|
||||
# British English translation for gnome-shell.
|
||||
# Copyright (C) 2009 gnome-shell's COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
# Philip Withnall <philip@tecnocode.co.uk>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell master\n"
|
||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
|
||||
"shell&component=general\n"
|
||||
"POT-Creation-Date: 2009-09-12 12:41+0000\n"
|
||||
"PO-Revision-Date: 2009-09-12 12:41+0000\n"
|
||||
"Last-Translator: Philip Withnall <philip@tecnocode.co.uk>\n"
|
||||
"Language-Team: British English <en_GB@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "GNOME Shell"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Window management and application launching"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:269
|
||||
msgid "Activities"
|
||||
msgstr "Activities"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:452
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %l:%M %p"
|
||||
|
||||
#: ../js/ui/dash.js:283
|
||||
msgid "Find..."
|
||||
msgstr "Find…"
|
||||
|
||||
#: ../js/ui/dash.js:400
|
||||
msgid "Browse"
|
||||
msgstr "Browse"
|
||||
|
||||
#: ../js/ui/dash.js:536
|
||||
msgid "(see all)"
|
||||
msgstr "(see all)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:753 ../js/ui/dash.js:809
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "APPLICATIONS"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:773
|
||||
msgid "PLACES"
|
||||
msgstr "PLACES"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:780 ../js/ui/dash.js:819
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "RECENT DOCUMENTS"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:799 ../js/ui/dash.js:931
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "SEARCH RESULTS"
|
||||
|
||||
#: ../js/ui/dash.js:814
|
||||
msgid "PREFERENCES"
|
||||
msgstr "PREFERENCES"
|
||||
|
||||
#: ../js/ui/runDialog.js:90
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Please enter a command:"
|
||||
|
||||
#: ../src/shell-global.c:799
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Less than a minute ago"
|
||||
|
||||
#: ../src/shell-global.c:802
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "%d minute ago"
|
||||
msgstr[1] "%d minutes ago"
|
||||
|
||||
#: ../src/shell-global.c:805
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "%d hour ago"
|
||||
msgstr[1] "%d hours ago"
|
||||
|
||||
#: ../src/shell-global.c:808
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "%d day ago"
|
||||
msgstr[1] "%d days ago"
|
||||
|
||||
#: ../src/shell-global.c:811
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "%d week ago"
|
||||
msgstr[1] "%d weeks ago"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "Unknown"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "Can't lock screen: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr "Can't temporarily set screensaver to blank screen: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "Can't logout: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "Account Information…"
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "Sidebar"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "System Preferences…"
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "Lock Screen"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "Switch User"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "Log Out…"
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "Shut Down…"
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "Home Folder"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "File System"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "Search"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
40
po/es.po
40
po/es.po
@ -8,13 +8,13 @@ msgstr ""
|
||||
"Project-Id-Version: gnome-shell master\n"
|
||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
|
||||
"shell&component=general\n"
|
||||
"POT-Creation-Date: 2009-08-28 20:35+0000\n"
|
||||
"PO-Revision-Date: 2009-08-30 11:16+0200\n"
|
||||
"POT-Creation-Date: 2009-09-11 21:48+0000\n"
|
||||
"PO-Revision-Date: 2009-09-12 14:40+0200\n"
|
||||
"Last-Translator: Jorge González <jorgegonz@svn.gnome.org>\n"
|
||||
"Language-Team: Español <gnome-es-list@gnome.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Content-Transfer-Encoding: UTF-8\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
@ -26,79 +26,83 @@ msgid "Window management and application launching"
|
||||
msgstr "Gestión de ventanas e inicio de aplicaciones"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:271
|
||||
#: ../js/ui/panel.js:269
|
||||
msgid "Activities"
|
||||
msgstr "Actividades"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:451
|
||||
#: ../js/ui/panel.js:452
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %H:%M"
|
||||
|
||||
#: ../js/ui/dash.js:256
|
||||
#: ../js/ui/dash.js:283
|
||||
msgid "Find..."
|
||||
msgstr "Buscar…"
|
||||
|
||||
#: ../js/ui/dash.js:374
|
||||
#: ../js/ui/dash.js:400
|
||||
msgid "Browse"
|
||||
msgstr "Examine"
|
||||
|
||||
#: ../js/ui/dash.js:451
|
||||
#: ../js/ui/dash.js:536
|
||||
msgid "(see all)"
|
||||
msgstr "(ver todo)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:634 ../js/ui/dash.js:682
|
||||
#: ../js/ui/dash.js:736 ../js/ui/dash.js:792
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "APLICACIONES"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:654
|
||||
#: ../js/ui/dash.js:756
|
||||
msgid "PLACES"
|
||||
msgstr "LUGARES"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:661 ../js/ui/dash.js:694
|
||||
#: ../js/ui/dash.js:763 ../js/ui/dash.js:802
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "DOCUMENTOS RECIENTES"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:680
|
||||
#: ../js/ui/dash.js:782 ../js/ui/dash.js:907
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "RESULTADOS DE LA BÚSQUEDA"
|
||||
|
||||
#: ../js/ui/runDialog.js:82
|
||||
#: ../js/ui/dash.js:797
|
||||
msgid "PREFERENCES"
|
||||
msgstr "PREFERENCIAS"
|
||||
|
||||
#: ../js/ui/runDialog.js:90
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Introduzca un comando:"
|
||||
|
||||
#: ../src/shell-global.c:840
|
||||
#: ../src/shell-global.c:799
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Hace menos de un minuto"
|
||||
|
||||
#: ../src/shell-global.c:843
|
||||
#: ../src/shell-global.c:802
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "Hace %d minuto"
|
||||
msgstr[1] "Hace %d minutos"
|
||||
|
||||
#: ../src/shell-global.c:846
|
||||
#: ../src/shell-global.c:805
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "Hace %d hora"
|
||||
msgstr[1] "Hace %d horas"
|
||||
|
||||
#: ../src/shell-global.c:849
|
||||
#: ../src/shell-global.c:808
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "Hace %d día"
|
||||
msgstr[1] "Hace %d días"
|
||||
|
||||
#: ../src/shell-global.c:852
|
||||
#: ../src/shell-global.c:811
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
|
177
po/fr.po
177
po/fr.po
@ -1,21 +1,182 @@
|
||||
# French translations for gnome-shell package.
|
||||
# Copyright (C) 2009 THE gnome-shell'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
# Colin Walters <walters@verbum.org>, 2009.
|
||||
#
|
||||
# Mathieu Bridon <bochecha@fedoraproject.org>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell 0.0.1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-07-27 15:09-0400\n"
|
||||
"PO-Revision-Date: 2009-07-27 15:23-0400\n"
|
||||
"Last-Translator: Colin Walters <walters@verbum.org>\n"
|
||||
"Language-Team: French\n"
|
||||
"Project-Id-Version: HEAD\n"
|
||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
|
||||
"shell&component=general\n"
|
||||
"POT-Creation-Date: 2009-09-09 21:30+0000\n"
|
||||
"PO-Revision-Date: 2009-09-11 21:40+0200\n"
|
||||
"Last-Translator: Mathieu Bridon <bochecha@fedoraproject.org>\n"
|
||||
"Language-Team: GNOME French Team\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: ../js/ui/panel.js:74
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "GNOME Shell"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Gestion des fenêtres et lancement des applications"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:269
|
||||
msgid "Activities"
|
||||
msgstr "Activités"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:452
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %H:%M"
|
||||
|
||||
#: ../js/ui/dash.js:255
|
||||
msgid "Find..."
|
||||
msgstr "Rechercher..."
|
||||
|
||||
#: ../js/ui/dash.js:372
|
||||
msgid "Browse"
|
||||
msgstr "Parcourir"
|
||||
|
||||
#: ../js/ui/dash.js:508
|
||||
msgid "(see all)"
|
||||
msgstr "(tout afficher)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:700 ../js/ui/dash.js:756 ../js/ui/dash.js:887
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "APPLICATIONS"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:720
|
||||
msgid "PLACES"
|
||||
msgstr "RACCOURCIS"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:727 ../js/ui/dash.js:768 ../js/ui/dash.js:861
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "DOCUMENTS RÉCENTS"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:746 ../js/ui/dash.js:850 ../js/ui/dash.js:876
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "RÉSULTATS DE LA RECHERCHE"
|
||||
|
||||
#: ../js/ui/runDialog.js:90
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Veuillez saisir une commande :"
|
||||
|
||||
#: ../src/shell-global.c:799
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Il y a moins d'une minute"
|
||||
|
||||
#: ../src/shell-global.c:802
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "Il y a %d minute"
|
||||
msgstr[1] "Il y a %d minutes"
|
||||
|
||||
#: ../src/shell-global.c:805
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "Il y a %d heure"
|
||||
msgstr[1] "Il y a %d heures"
|
||||
|
||||
#: ../src/shell-global.c:808
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "Il y a %d jour"
|
||||
msgstr[1] "Il y a %d jours"
|
||||
|
||||
#: ../src/shell-global.c:811
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "Il y a %d semaine"
|
||||
msgstr[1] "Il y a %d semaines"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "Inconnu"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "Impossible de verrouiller l'écran : %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr ""
|
||||
"Impossible de régler temporairement l'écran de veille sur un écran vide : %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "Impossible de fermer la session : %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "Informations personnelles..."
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "Barre latérale"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "Préférences du système..."
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "Verrouiller l'écran"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "Changer d'utilisateur"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "Fermer la session..."
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "Éteindre..."
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "Dossier personnel"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "Système de fichiers"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "Recherche"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s : %2$s"
|
||||
|
56
po/gl.po
56
po/gl.po
@ -7,8 +7,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell master\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-08-22 16:39+0200\n"
|
||||
"PO-Revision-Date: 2009-08-18 21:20+0100\n"
|
||||
"POT-Creation-Date: 2009-09-15 23:06+0200\n"
|
||||
"PO-Revision-Date: 2009-09-10 22:32+0100\n"
|
||||
"Last-Translator: Fran Diéguez <fran.dieguez@glug.es>\n"
|
||||
"Language-Team: Galician <gnome@mancomun.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@ -25,80 +25,83 @@ msgid "Window management and application launching"
|
||||
msgstr "Xestor de xanelas e lanzado de aplicativos"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:266
|
||||
#: ../js/ui/panel.js:269
|
||||
msgid "Activities"
|
||||
msgstr "Actividades"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:433
|
||||
#: ../js/ui/panel.js:452
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %l:%M %p"
|
||||
|
||||
#: ../js/ui/dash.js:250
|
||||
msgid "Find apps or documents"
|
||||
msgstr "Atopar aplicativos ou documentos"
|
||||
#: ../js/ui/dash.js:283
|
||||
msgid "Find..."
|
||||
msgstr "Buscar..."
|
||||
|
||||
#: ../js/ui/dash.js:368
|
||||
#: ../js/ui/dash.js:400
|
||||
msgid "Browse"
|
||||
msgstr "Explorar"
|
||||
|
||||
#: ../js/ui/dash.js:536
|
||||
msgid "(see all)"
|
||||
msgstr "(ver todos)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:556 ../js/ui/dash.js:606
|
||||
#: ../js/ui/dash.js:753 ../js/ui/dash.js:809
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "APLICATIVOS"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:576
|
||||
#: ../js/ui/dash.js:773
|
||||
msgid "PLACES"
|
||||
msgstr "LUGARES"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:583
|
||||
#: ../js/ui/dash.js:780 ../js/ui/dash.js:819
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "DOCUMENTOS RECENTES"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:602
|
||||
#: ../js/ui/dash.js:799 ../js/ui/dash.js:931
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "RESULTADOS DA BÚSQUEDA"
|
||||
|
||||
#: ../js/ui/dash.js:814
|
||||
msgid "PREFERENCES"
|
||||
msgstr ""
|
||||
|
||||
#: ../js/ui/dash.js:615
|
||||
#, fuzzy
|
||||
msgid "DOCUMENTS"
|
||||
msgstr "DOCUMENTOS RECENTES"
|
||||
|
||||
#: ../js/ui/runDialog.js:75
|
||||
#: ../js/ui/runDialog.js:96
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Insira unha orde:"
|
||||
|
||||
#: ../src/shell-global.c:841
|
||||
#: ../src/shell-global.c:799
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Menos de un minuto"
|
||||
|
||||
#: ../src/shell-global.c:844
|
||||
#: ../src/shell-global.c:802
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "fai %d minuto"
|
||||
msgstr[1] "fai %d minutos"
|
||||
|
||||
#: ../src/shell-global.c:847
|
||||
#: ../src/shell-global.c:805
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "fai %d hora"
|
||||
msgstr[1] "fai %d horas"
|
||||
|
||||
#: ../src/shell-global.c:850
|
||||
#: ../src/shell-global.c:808
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "fai %d día"
|
||||
msgstr[1] "fai %d días"
|
||||
|
||||
#: ../src/shell-global.c:853
|
||||
#: ../src/shell-global.c:811
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
@ -180,5 +183,12 @@ msgstr "Buscar"
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
|
||||
#~ msgid "Find apps or documents"
|
||||
#~ msgstr "Atopar aplicativos ou documentos"
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid "DOCUMENTS"
|
||||
#~ msgstr "DOCUMENTOS RECENTES"
|
||||
|
||||
#~ msgid "Manager"
|
||||
#~ msgstr "Xestor"
|
||||
|
59
po/it.po
59
po/it.po
@ -6,9 +6,10 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-08-20 23:25+0200\n"
|
||||
"PO-Revision-Date: 2009-08-20 23:26+0200\n"
|
||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
|
||||
"shell&component=general\n"
|
||||
"POT-Creation-Date: 2009-09-05 00:19+0000\n"
|
||||
"PO-Revision-Date: 2009-09-06 18:31+0200\n"
|
||||
"Last-Translator: Milo Casagrande <milo@ubuntu.com>\n"
|
||||
"Language-Team: Italian <tp@lists.linux.it>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@ -25,72 +26,80 @@ msgid "Window management and application launching"
|
||||
msgstr "Gestione finestre e avvio applicazioni"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:266
|
||||
#: ../js/ui/panel.js:271
|
||||
msgid "Activities"
|
||||
msgstr "Attività"
|
||||
|
||||
# (ndt) proviamo col k, se non funge, sappiamo il perché...
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:433
|
||||
#: ../js/ui/panel.js:454
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %k.%M"
|
||||
|
||||
# (ndt) è da valutare se è troppo lunga, è in una casella di ricerca
|
||||
#: ../js/ui/dash.js:251
|
||||
msgid "Find apps or documents"
|
||||
msgstr "Trova programmi e documenti"
|
||||
#: ../js/ui/dash.js:256
|
||||
msgid "Find..."
|
||||
msgstr "Trova..."
|
||||
|
||||
#: ../js/ui/dash.js:369
|
||||
#: ../js/ui/dash.js:374
|
||||
msgid "Browse"
|
||||
msgstr "Esplora"
|
||||
|
||||
#: ../js/ui/dash.js:511
|
||||
msgid "(see all)"
|
||||
msgstr "(vedi tutto)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:505 ../js/ui/dash.js:578
|
||||
#: ../js/ui/dash.js:705 ../js/ui/dash.js:761 ../js/ui/dash.js:893
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "Applicazioni"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:510 ../js/ui/dash.js:605
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "Documenti recenti"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:598
|
||||
#: ../js/ui/dash.js:725
|
||||
msgid "PLACES"
|
||||
msgstr "Risorse"
|
||||
|
||||
#: ../js/ui/runDialog.js:75
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:732 ../js/ui/dash.js:773 ../js/ui/dash.js:867
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "Documenti recenti"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:751 ../js/ui/dash.js:856 ../js/ui/dash.js:882
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "Risultati ricerca"
|
||||
|
||||
#: ../js/ui/runDialog.js:82
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Inserire un comando:"
|
||||
|
||||
#: ../src/shell-global.c:841
|
||||
#: ../src/shell-global.c:840
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Meno di un minuto fa"
|
||||
|
||||
#: ../src/shell-global.c:844
|
||||
#: ../src/shell-global.c:843
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "%d minuto fa"
|
||||
msgstr[1] "%d minuti fa"
|
||||
|
||||
#: ../src/shell-global.c:847
|
||||
#: ../src/shell-global.c:846
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "%d ora fa"
|
||||
msgstr[1] "%d ore fa"
|
||||
|
||||
#: ../src/shell-global.c:850
|
||||
#: ../src/shell-global.c:849
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "%d giorno fa"
|
||||
msgstr[1] "%d giorni fa"
|
||||
|
||||
#: ../src/shell-global.c:853
|
||||
#: ../src/shell-global.c:852
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
@ -175,6 +184,10 @@ msgstr "Cerca"
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
|
||||
# (ndt) è da valutare se è troppo lunga, è in una casella di ricerca
|
||||
#~ msgid "Find apps or documents"
|
||||
#~ msgstr "Trova programmi e documenti"
|
||||
|
||||
# (ndt) no idea...
|
||||
#~ msgid "Manager"
|
||||
#~ msgstr "Manager"
|
||||
|
59
po/pl.po
59
po/pl.po
@ -8,8 +8,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-08-18 23:25+0200\n"
|
||||
"PO-Revision-Date: 2009-08-18 23:23+0100\n"
|
||||
"POT-Creation-Date: 2009-09-09 03:06+0200\n"
|
||||
"PO-Revision-Date: 2009-09-09 03:02+0100\n"
|
||||
"Last-Translator: Tomasz Dominikowski <dominikowski@gmail.com>\n"
|
||||
"Language-Team: Polish <gnomepl@aviary.pl>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@ -29,57 +29,58 @@ msgid "Window management and application launching"
|
||||
msgstr "Zarządzanie oknami i uruchamianiem programów"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:266
|
||||
#: ../js/ui/panel.js:269
|
||||
msgid "Activities"
|
||||
msgstr "Czynności"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:433
|
||||
#: ../js/ui/panel.js:452
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a, %H:%M"
|
||||
|
||||
#: ../js/ui/dash.js:251
|
||||
msgid "Find apps or documents"
|
||||
msgstr "Wyszukuje programy lub dokumenty"
|
||||
#: ../js/ui/dash.js:255
|
||||
msgid "Find..."
|
||||
msgstr "Znajdź..."
|
||||
|
||||
#: ../js/ui/dash.js:369
|
||||
#: ../js/ui/dash.js:372
|
||||
msgid "Browse"
|
||||
msgstr "Przeglądaj"
|
||||
|
||||
#: ../js/ui/dash.js:508
|
||||
msgid "(see all)"
|
||||
msgstr "(wyświetl wszystko)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:505 ../js/ui/dash.js:578
|
||||
#: ../js/ui/dash.js:700 ../js/ui/dash.js:756 ../js/ui/dash.js:887
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "Programy"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:510 ../js/ui/dash.js:605
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "Ostatnie dokumenty"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:598
|
||||
#: ../js/ui/dash.js:720
|
||||
msgid "PLACES"
|
||||
msgstr "Miejsca"
|
||||
|
||||
#: ../js/ui/runDialog.js:74
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:727 ../js/ui/dash.js:768 ../js/ui/dash.js:861
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "Ostatnie dokumenty"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:746 ../js/ui/dash.js:850 ../js/ui/dash.js:876
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "Wyniki wyszukiwania"
|
||||
|
||||
#: ../js/ui/runDialog.js:90
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Proszę wprowadzić polecenie:"
|
||||
|
||||
#: ../src/gdmuser/gdm-user.c:243
|
||||
msgid "Manager"
|
||||
msgstr "Menedżer"
|
||||
|
||||
#: ../src/gdmuser/gdm-user.c:244
|
||||
msgid "The user manager object this user is controlled by."
|
||||
msgstr "Obiekt menedżera użytkowników, który steruje tym użytkownikiem."
|
||||
|
||||
#: ../src/shell-global.c:841
|
||||
#: ../src/shell-global.c:799
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Mniej niż minutę temu"
|
||||
|
||||
#: ../src/shell-global.c:844
|
||||
#: ../src/shell-global.c:802
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
@ -87,7 +88,7 @@ msgstr[0] "%d minuta temu"
|
||||
msgstr[1] "%d minuty temu"
|
||||
msgstr[2] "%d minut temu"
|
||||
|
||||
#: ../src/shell-global.c:847
|
||||
#: ../src/shell-global.c:805
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
@ -95,7 +96,7 @@ msgstr[0] "%d godzina temu"
|
||||
msgstr[1] "%d godziny temu"
|
||||
msgstr[2] "%d godzin temu"
|
||||
|
||||
#: ../src/shell-global.c:850
|
||||
#: ../src/shell-global.c:808
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
@ -103,7 +104,7 @@ msgstr[0] "%d dzień temu"
|
||||
msgstr[1] "%d dni temu"
|
||||
msgstr[2] "%d dni temu"
|
||||
|
||||
#: ../src/shell-global.c:853
|
||||
#: ../src/shell-global.c:811
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
|
117
src/Makefile-nbtk.am
Normal file
117
src/Makefile-nbtk.am
Normal 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
36
src/Makefile-toolkit.am
Normal 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
|
@ -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 = \
|
||||
@ -75,6 +78,8 @@ libgnome_shell_la_SOURCES = \
|
||||
shell-generic-container.h \
|
||||
shell-gtk-embed.c \
|
||||
shell-gtk-embed.h \
|
||||
shell-menu.c \
|
||||
shell-menu.h \
|
||||
shell-overflow-list.c \
|
||||
shell-overflow-list.h \
|
||||
shell-process.c \
|
||||
@ -94,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 = \
|
||||
@ -112,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)
|
||||
@ -123,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
|
||||
@ -150,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 \
|
||||
@ -167,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)) \
|
||||
@ -177,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 \
|
||||
@ -201,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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -253,6 +253,7 @@ if options.debug:
|
||||
normal_exit = False
|
||||
|
||||
try:
|
||||
shell = None
|
||||
if options.xephyr:
|
||||
xephyr = start_xephyr()
|
||||
# This makes us not grab the org.gnome.Panel name
|
||||
@ -281,7 +282,9 @@ finally:
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
if shell.returncode == 0:
|
||||
if shell is None:
|
||||
print "Failed to start shell"
|
||||
elif shell.returncode == 0:
|
||||
normal_exit = True
|
||||
if options.verbose:
|
||||
print "Shell exited normally"
|
||||
|
@ -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
768
src/nbtk/nbtk-adjustment.c
Normal 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
121
src/nbtk/nbtk-adjustment.h
Normal 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
739
src/nbtk/nbtk-bin.c
Normal 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
92
src/nbtk/nbtk-bin.h
Normal 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__ */
|
176
src/nbtk/nbtk-box-layout-child.c
Normal file
176
src/nbtk/nbtk-box-layout-child.c
Normal 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;
|
||||
}
|
84
src/nbtk/nbtk-box-layout-child.h
Normal file
84
src/nbtk/nbtk-box-layout-child.h
Normal 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
1252
src/nbtk/nbtk-box-layout.c
Normal file
File diff suppressed because it is too large
Load Diff
91
src/nbtk/nbtk-box-layout.h
Normal file
91
src/nbtk/nbtk-box-layout.h
Normal 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
690
src/nbtk/nbtk-button.c
Normal 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
90
src/nbtk/nbtk-button.h
Normal 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
367
src/nbtk/nbtk-clipboard.c
Normal 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 *) ¬ify_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
94
src/nbtk/nbtk-clipboard.h
Normal 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
897
src/nbtk/nbtk-entry.c
Normal 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
88
src/nbtk/nbtk-entry.h
Normal 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__ */
|
30
src/nbtk/nbtk-enum-types.c.in
Normal file
30
src/nbtk/nbtk-enum-types.c.in
Normal 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 ***/
|
29
src/nbtk/nbtk-enum-types.h.in
Normal file
29
src/nbtk/nbtk-enum-types.h.in
Normal 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
341
src/nbtk/nbtk-label.c
Normal 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
75
src/nbtk/nbtk-label.h
Normal 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__ */
|
12
src/nbtk/nbtk-marshal.list
Normal file
12
src/nbtk/nbtk-marshal.list
Normal 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
111
src/nbtk/nbtk-private.c
Normal 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
49
src/nbtk/nbtk-private.h
Normal 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
1065
src/nbtk/nbtk-scroll-bar.c
Normal file
File diff suppressed because it is too large
Load Diff
81
src/nbtk/nbtk-scroll-bar.h
Normal file
81
src/nbtk/nbtk-scroll-bar.h
Normal 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
829
src/nbtk/nbtk-scroll-view.c
Normal 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;
|
||||
}
|
87
src/nbtk/nbtk-scroll-view.h
Normal file
87
src/nbtk/nbtk-scroll-view.h
Normal 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__ */
|
96
src/nbtk/nbtk-scrollable.c
Normal file
96
src/nbtk/nbtk-scrollable.c
Normal 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);
|
||||
}
|
69
src/nbtk/nbtk-scrollable.h
Normal file
69
src/nbtk/nbtk-scrollable.h
Normal 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
575
src/nbtk/nbtk-subtexture.c
Normal 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;
|
||||
}
|
92
src/nbtk/nbtk-subtexture.h
Normal file
92
src/nbtk/nbtk-subtexture.h
Normal 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__ */
|
456
src/nbtk/nbtk-texture-cache.c
Normal file
456
src/nbtk/nbtk-texture-cache.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
94
src/nbtk/nbtk-texture-cache.h
Normal file
94
src/nbtk/nbtk-texture-cache.h
Normal 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 */
|
620
src/nbtk/nbtk-texture-frame.c
Normal file
620
src/nbtk/nbtk-texture-frame.c
Normal 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;
|
||||
}
|
92
src/nbtk/nbtk-texture-frame.h
Normal file
92
src/nbtk/nbtk-texture-frame.h
Normal 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
664
src/nbtk/nbtk-tooltip.c
Normal 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
79
src/nbtk/nbtk-tooltip.h
Normal 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
59
src/nbtk/nbtk-types.h
Normal 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
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
116
src/nbtk/nbtk-widget.h
Normal 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__ */
|
@ -437,9 +437,10 @@ get_app_for_window_direct (MetaWindow *window)
|
||||
|
||||
if (id != NULL)
|
||||
result = shell_app_system_load_from_desktop_file (appsys, id, NULL);
|
||||
else
|
||||
result = create_transient_app_for_window (window);
|
||||
}
|
||||
if (result == NULL)
|
||||
result = create_transient_app_for_window (window);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ struct _ShellAppSystemPrivate {
|
||||
};
|
||||
|
||||
static void shell_app_system_finalize (GObject *object);
|
||||
static void on_tree_changed (gpointer user_data);
|
||||
static gboolean on_tree_changed (gpointer user_data);
|
||||
static void on_tree_changed_cb (GMenuTree *tree, gpointer user_data);
|
||||
static void reread_menus (ShellAppSystem *self);
|
||||
static void on_favorite_apps_changed (GConfClient *client, guint id, GConfEntry *entry, gpointer user_data);
|
||||
@ -415,13 +415,14 @@ reread_menus (ShellAppSystem *self)
|
||||
cache_by_id (self, self->priv->cached_settings, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
on_tree_changed (gpointer user_data)
|
||||
{
|
||||
ShellAppSystem *self = SHELL_APP_SYSTEM (user_data);
|
||||
g_signal_emit (self, signals[INSTALLED_CHANGED], 0);
|
||||
reread_menus (self);
|
||||
self->priv->app_change_timeout_id = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -158,7 +158,7 @@ shell_button_box_button_release_event (ClutterActor *actor,
|
||||
|
||||
set_pressed (box, FALSE);
|
||||
|
||||
g_signal_emit (G_OBJECT (box), shell_button_box_signals[ACTIVATE], 0);
|
||||
g_signal_emit (G_OBJECT (box), shell_button_box_signals[ACTIVATE], 0, event);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -249,6 +249,7 @@ shell_button_box_class_init (ShellButtonBoxClass *klass)
|
||||
/**
|
||||
* ShellButtonBox::activate
|
||||
* @box: The #ShellButtonBox
|
||||
* @event: Release event which triggered the activation
|
||||
*
|
||||
* This signal is emitted when the button should take the action
|
||||
* associated with button click+release.
|
||||
@ -260,7 +261,7 @@ shell_button_box_class_init (ShellButtonBoxClass *klass)
|
||||
0,
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
G_TYPE_NONE, 1, CLUTTER_TYPE_EVENT);
|
||||
|
||||
/**
|
||||
* ShellButtonBox:active
|
||||
|
@ -146,6 +146,36 @@ shell_draw_clock (ClutterCairoTexture *texture,
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
void
|
||||
shell_draw_box_pointer (ClutterCairoTexture *texture,
|
||||
ClutterColor *border_color,
|
||||
ClutterColor *background_color)
|
||||
{
|
||||
guint width, height;
|
||||
cairo_t *cr;
|
||||
|
||||
clutter_cairo_texture_get_surface_size (texture, &width, &height);
|
||||
|
||||
clutter_cairo_texture_clear (texture);
|
||||
cr = clutter_cairo_texture_create (texture);
|
||||
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
|
||||
clutter_cairo_set_source_color (cr, border_color);
|
||||
|
||||
cairo_move_to (cr, width, 0);
|
||||
cairo_line_to (cr, 0, floor (height * 0.5));
|
||||
cairo_line_to (cr, width, height);
|
||||
|
||||
cairo_stroke_preserve (cr);
|
||||
|
||||
clutter_cairo_set_source_color (cr, background_color);
|
||||
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
hook_paint_red_border (ClutterActor *actor,
|
||||
gpointer user_data)
|
||||
|
@ -13,6 +13,10 @@ ClutterCairoTexture *shell_create_vertical_gradient (ClutterColor *top,
|
||||
ClutterCairoTexture *shell_create_horizontal_gradient (ClutterColor *left,
|
||||
ClutterColor *right);
|
||||
|
||||
void shell_draw_box_pointer (ClutterCairoTexture *texture,
|
||||
ClutterColor *border_color,
|
||||
ClutterColor *background_color);
|
||||
|
||||
void shell_draw_clock (ClutterCairoTexture *texture,
|
||||
int hour,
|
||||
int minute);
|
||||
|
@ -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",
|
||||
@ -295,47 +308,6 @@ shell_clutter_texture_set_from_pixbuf (ClutterTexture *texture,
|
||||
0, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_get_event_key_symbol:
|
||||
*
|
||||
* Return value: Clutter key value for the key press and release events,
|
||||
* as specified in clutter-keysyms.h
|
||||
*/
|
||||
guint16
|
||||
shell_get_event_key_symbol(ClutterEvent *event)
|
||||
{
|
||||
g_return_val_if_fail(event->type == CLUTTER_KEY_PRESS ||
|
||||
event->type == CLUTTER_KEY_RELEASE, 0);
|
||||
|
||||
return event->key.keyval;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_get_button_event_click_count:
|
||||
*
|
||||
* Return value: click count for button press and release events
|
||||
*/
|
||||
guint16
|
||||
shell_get_button_event_click_count(ClutterEvent *event)
|
||||
{
|
||||
g_return_val_if_fail(event->type == CLUTTER_BUTTON_PRESS ||
|
||||
event->type == CLUTTER_BUTTON_RELEASE, 0);
|
||||
return event->button.click_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_get_event_related:
|
||||
*
|
||||
* Return value: (transfer none): related actor
|
||||
*/
|
||||
ClutterActor *
|
||||
shell_get_event_related (ClutterEvent *event)
|
||||
{
|
||||
g_return_val_if_fail (event->type == CLUTTER_ENTER ||
|
||||
event->type == CLUTTER_LEAVE, NULL);
|
||||
return event->crossing.related;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_get:
|
||||
*
|
||||
|
@ -36,10 +36,6 @@ GType shell_global_get_type (void) G_GNUC_CONST;
|
||||
gboolean shell_clutter_texture_set_from_pixbuf (ClutterTexture *texture,
|
||||
GdkPixbuf *pixbuf);
|
||||
|
||||
guint16 shell_get_event_key_symbol(ClutterEvent *event);
|
||||
|
||||
guint16 shell_get_button_event_click_count(ClutterEvent *event);
|
||||
|
||||
ClutterActor *shell_get_event_related(ClutterEvent *event);
|
||||
|
||||
ShellGlobal *shell_global_get (void);
|
||||
|
335
src/shell-menu.c
Normal file
335
src/shell-menu.c
Normal file
@ -0,0 +1,335 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/**
|
||||
* SECTION:shell-menu
|
||||
* @short_description: A box which acts like a popup menu
|
||||
*
|
||||
* A #BigBox subclass which adds methods and signals useful for implementing
|
||||
* popup-menu like actors.
|
||||
*/
|
||||
|
||||
#include "shell-menu.h"
|
||||
|
||||
G_DEFINE_TYPE(ShellMenu, shell_menu, BIG_TYPE_BOX);
|
||||
|
||||
struct _ShellMenuPrivate {
|
||||
gboolean popped_up;
|
||||
gboolean have_grab;
|
||||
|
||||
gboolean released_on_source;
|
||||
ClutterActor *source_actor;
|
||||
|
||||
ClutterActor *selected;
|
||||
};
|
||||
|
||||
/* Signals */
|
||||
enum
|
||||
{
|
||||
UNSELECTED,
|
||||
SELECTED,
|
||||
ACTIVATE,
|
||||
CANCELLED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint shell_menu_signals [LAST_SIGNAL] = { 0 };
|
||||
|
||||
static gboolean
|
||||
container_contains (ClutterContainer *container,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
while (actor != NULL && actor != (ClutterActor*)container)
|
||||
{
|
||||
actor = clutter_actor_get_parent (actor);
|
||||
}
|
||||
return actor != NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
shell_menu_popdown_nosignal (ShellMenu *box)
|
||||
{
|
||||
box->priv->popped_up = FALSE;
|
||||
if (box->priv->have_grab)
|
||||
clutter_ungrab_pointer ();
|
||||
clutter_actor_hide (CLUTTER_ACTOR (box));
|
||||
}
|
||||
|
||||
static void
|
||||
on_selected_destroy (ClutterActor *actor,
|
||||
ShellMenu *box)
|
||||
{
|
||||
box->priv->selected = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
set_selected (ShellMenu *box,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
if (actor == box->priv->selected)
|
||||
return;
|
||||
if (box->priv->selected)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (box->priv->selected, G_CALLBACK(on_selected_destroy), box);
|
||||
g_signal_emit (G_OBJECT (box), shell_menu_signals[UNSELECTED], 0, box->priv->selected);
|
||||
}
|
||||
box->priv->selected = actor;
|
||||
if (box->priv->selected)
|
||||
{
|
||||
g_signal_connect (box->priv->selected, "destroy", G_CALLBACK(on_selected_destroy), box);
|
||||
g_signal_emit (G_OBJECT (box), shell_menu_signals[SELECTED], 0, box->priv->selected);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
shell_menu_enter_event (ClutterActor *actor,
|
||||
ClutterCrossingEvent *event)
|
||||
{
|
||||
ShellMenu *box = SHELL_MENU (actor);
|
||||
|
||||
if (!container_contains (CLUTTER_CONTAINER (box), event->source))
|
||||
return TRUE;
|
||||
|
||||
if (event->source == (ClutterActor*)box)
|
||||
return TRUE;
|
||||
|
||||
if (g_object_get_data (G_OBJECT (event->source), "shell-is-separator"))
|
||||
return TRUE;
|
||||
|
||||
set_selected (box, event->source);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
shell_menu_leave_event (ClutterActor *actor,
|
||||
ClutterCrossingEvent *event)
|
||||
{
|
||||
ShellMenu *box = SHELL_MENU (actor);
|
||||
|
||||
set_selected (box, NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
shell_menu_button_release_event (ClutterActor *actor,
|
||||
ClutterButtonEvent *event)
|
||||
{
|
||||
ShellMenu *box = SHELL_MENU (actor);
|
||||
|
||||
if (event->button != 1)
|
||||
return FALSE;
|
||||
|
||||
if (box->priv->source_actor && !box->priv->released_on_source)
|
||||
{
|
||||
if (box->priv->source_actor == event->source ||
|
||||
(CLUTTER_IS_CONTAINER (box->priv->source_actor) &&
|
||||
container_contains (CLUTTER_CONTAINER (box->priv->source_actor), event->source)))
|
||||
{
|
||||
/* On the next release, we want to pop down the menu regardless */
|
||||
box->priv->released_on_source = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
shell_menu_popdown_nosignal (box);
|
||||
|
||||
if (!container_contains (CLUTTER_CONTAINER (box), event->source))
|
||||
{
|
||||
g_signal_emit (G_OBJECT (box), shell_menu_signals[CANCELLED], 0);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (box->priv->selected == NULL)
|
||||
{
|
||||
g_signal_emit (G_OBJECT (box), shell_menu_signals[CANCELLED], 0);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_signal_emit (G_OBJECT (box), shell_menu_signals[ACTIVATE], 0, box->priv->selected);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
shell_menu_popup (ShellMenu *box,
|
||||
guint button,
|
||||
guint32 activate_time)
|
||||
{
|
||||
if (box->priv->popped_up)
|
||||
return;
|
||||
box->priv->popped_up = TRUE;
|
||||
box->priv->have_grab = TRUE;
|
||||
box->priv->released_on_source = FALSE;
|
||||
clutter_grab_pointer (CLUTTER_ACTOR (box));
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_menu_popdown:
|
||||
* @box:
|
||||
*
|
||||
* If the menu is currently active, hide it, emitting the 'cancelled' signal.
|
||||
*/
|
||||
void
|
||||
shell_menu_popdown (ShellMenu *box)
|
||||
{
|
||||
if (!box->priv->popped_up)
|
||||
return;
|
||||
shell_menu_popdown_nosignal (box);
|
||||
g_signal_emit (G_OBJECT (box), shell_menu_signals[CANCELLED], 0);
|
||||
}
|
||||
|
||||
static void
|
||||
on_source_destroyed (ClutterActor *actor,
|
||||
ShellMenu *box)
|
||||
{
|
||||
box->priv->source_actor = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_menu_set_persistent_source:
|
||||
* @box:
|
||||
* @source: Actor to use as menu origin
|
||||
*
|
||||
* This function changes the menu behavior on button release. Normally
|
||||
* when the mouse is released anywhere, the menu "pops down"; when this
|
||||
* function is called, if the mouse is released over the source actor,
|
||||
* the menu stays.
|
||||
*
|
||||
* The given @source actor must be reactive for this function to work.
|
||||
*/
|
||||
void
|
||||
shell_menu_set_persistent_source (ShellMenu *box,
|
||||
ClutterActor *source)
|
||||
{
|
||||
if (box->priv->source_actor)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (G_OBJECT (box->priv->source_actor),
|
||||
G_CALLBACK (on_source_destroyed),
|
||||
box);
|
||||
}
|
||||
box->priv->source_actor = source;
|
||||
if (box->priv->source_actor)
|
||||
{
|
||||
g_signal_connect (G_OBJECT (box->priv->source_actor),
|
||||
"destroy",
|
||||
G_CALLBACK (on_source_destroyed),
|
||||
box);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_menu_append_separator:
|
||||
* @box:
|
||||
* @separator: An actor which functions as a menu separator
|
||||
* @flags: Packing flags
|
||||
*
|
||||
* Actors added to the menu with default functions are treated like
|
||||
* menu items; this function will add an actor that should instead
|
||||
* be treated like a menu separator. The current practical effect
|
||||
* is that the separators will not be selectable.
|
||||
*/
|
||||
void
|
||||
shell_menu_append_separator (ShellMenu *box,
|
||||
ClutterActor *separator,
|
||||
BigBoxPackFlags flags)
|
||||
{
|
||||
g_object_set_data (G_OBJECT (separator), "shell-is-separator", GUINT_TO_POINTER(TRUE));
|
||||
big_box_append (BIG_BOX (box), separator, flags);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_menu_dispose (GObject *gobject)
|
||||
{
|
||||
ShellMenu *self = SHELL_MENU (gobject);
|
||||
|
||||
shell_menu_set_persistent_source (self, NULL);
|
||||
|
||||
G_OBJECT_CLASS (shell_menu_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_menu_class_init (ShellMenuClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
|
||||
gobject_class->dispose = shell_menu_dispose;
|
||||
|
||||
actor_class->enter_event = shell_menu_enter_event;
|
||||
actor_class->leave_event = shell_menu_leave_event;
|
||||
actor_class->button_release_event = shell_menu_button_release_event;
|
||||
|
||||
/**
|
||||
* ShellMenu::unselected
|
||||
* @box: The #ShellMenu
|
||||
* @actor: The previously hovered-over menu item
|
||||
*
|
||||
* This signal is emitted when a menu item transitions to
|
||||
* an unselected state.
|
||||
*/
|
||||
shell_menu_signals[UNSELECTED] =
|
||||
g_signal_new ("unselected",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR);
|
||||
|
||||
/**
|
||||
* ShellMenu::selected
|
||||
* @box: The #ShellMenu
|
||||
* @actor: The hovered-over menu item
|
||||
*
|
||||
* This signal is emitted when a menu item is in a selected state.
|
||||
*/
|
||||
shell_menu_signals[SELECTED] =
|
||||
g_signal_new ("selected",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR);
|
||||
|
||||
/**
|
||||
* ShellMenu::activate
|
||||
* @box: The #ShellMenu
|
||||
* @actor: The clicked menu item
|
||||
*
|
||||
* This signal is emitted when a menu item is selected.
|
||||
*/
|
||||
shell_menu_signals[ACTIVATE] =
|
||||
g_signal_new ("activate",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR);
|
||||
|
||||
/**
|
||||
* ShellMenu::cancelled
|
||||
* @box: The #ShellMenu
|
||||
*
|
||||
* This signal is emitted when the menu is closed without an option selected.
|
||||
*/
|
||||
shell_menu_signals[CANCELLED] =
|
||||
g_signal_new ("cancelled",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
g_type_class_add_private (gobject_class, sizeof (ShellMenuPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
shell_menu_init (ShellMenu *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, SHELL_TYPE_MENU,
|
||||
ShellMenuPrivate);
|
||||
}
|
41
src/shell-menu.h
Normal file
41
src/shell-menu.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef __SHELL_MENU_H__
|
||||
#define __SHELL_MENU_H__
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include "big/box.h"
|
||||
|
||||
#define SHELL_TYPE_MENU (shell_menu_get_type ())
|
||||
#define SHELL_MENU(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_MENU, ShellMenu))
|
||||
#define SHELL_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_MENU, ShellMenuClass))
|
||||
#define SHELL_IS_MENU(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_MENU))
|
||||
#define SHELL_IS_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_MENU))
|
||||
#define SHELL_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_MENU, ShellMenuClass))
|
||||
|
||||
typedef struct _ShellMenu ShellMenu;
|
||||
typedef struct _ShellMenuClass ShellMenuClass;
|
||||
|
||||
typedef struct _ShellMenuPrivate ShellMenuPrivate;
|
||||
|
||||
struct _ShellMenu
|
||||
{
|
||||
BigBox parent;
|
||||
|
||||
ShellMenuPrivate *priv;
|
||||
};
|
||||
|
||||
struct _ShellMenuClass
|
||||
{
|
||||
BigBoxClass parent_class;
|
||||
};
|
||||
|
||||
GType shell_menu_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void shell_menu_popup (ShellMenu *behavior, guint button, guint32 activate_time);
|
||||
|
||||
void shell_menu_set_persistent_source (ShellMenu *behavior, ClutterActor *source);
|
||||
|
||||
void shell_menu_append_separator (ShellMenu *behavior, ClutterActor *separator, BigBoxPackFlags flags);
|
||||
|
||||
void shell_menu_popdown (ShellMenu *behavior);
|
||||
|
||||
#endif /* __SHELL_MENU_H__ */
|
@ -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;
|
||||
}
|
@ -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__ */
|
92
src/toolkit/shell-border-image.c
Normal file
92
src/toolkit/shell-border-image.c
Normal 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;
|
||||
}
|
38
src/toolkit/shell-border-image.h
Normal file
38
src/toolkit/shell-border-image.h
Normal 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__ */
|
218
src/toolkit/shell-theme-context.c
Normal file
218
src/toolkit/shell-theme-context.c
Normal 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;
|
||||
}
|
40
src/toolkit/shell-theme-context.h
Normal file
40
src/toolkit/shell-theme-context.h
Normal 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__ */
|
2113
src/toolkit/shell-theme-node.c
Normal file
2113
src/toolkit/shell-theme-node.c
Normal file
File diff suppressed because it is too large
Load Diff
143
src/toolkit/shell-theme-node.h
Normal file
143
src/toolkit/shell-theme-node.h
Normal 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__ */
|
20
src/toolkit/shell-theme-private.h
Normal file
20
src/toolkit/shell-theme-private.h
Normal 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__ */
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user