Compare commits

..

230 Commits

Author SHA1 Message Date
d5dc5c0ddf Merge branch 'dorota.czaplejewicz/squeekboard-font_size' into 'font_size'
Cast later to avoid rounding to zero

See merge request dorota.czaplejewicz/squeekboard!1
2019-08-01 17:23:09 +00:00
172ed08d40 Cast later to avoid rounding to zero 2019-08-01 17:17:44 +00:00
f27fade744 fonts: Reset font size to a constant
The font size will only be affected by the scaling factor, and not by an attempt to fit the labels into buttons.

Left to do: adjust it based on CSS.
2019-08-01 16:35:33 +00:00
3085a10507 Merge branch 'cleanup' into 'master'
xml: Remove unused file

See merge request Librem5/squeekboard!110
2019-08-01 15:06:43 +00:00
b5f0aa423b xml: Remove unused file 2019-08-01 14:16:01 +00:00
c8bc2c424f Merge branch 'errors' into 'master'
Errors

See merge request Librem5/squeekboard!107
2019-07-31 18:54:15 +00:00
46fa6d4500 Merge branch 'rust_tests' into 'master'
Rust tests

See merge request Librem5/squeekboard!106
2019-07-31 17:11:33 +00:00
6002774f95 Merge branch 'imservice_cleanups' into 'master'
Imservice cleanups

See merge request Librem5/squeekboard!105
2019-07-31 14:27:13 +00:00
f7f208883c errors: Make compilation stricter 2019-07-31 14:11:49 +00:00
5523b00442 test: Add missing gtk include 2019-07-31 14:11:35 +00:00
c81fdb18de eekelement: Fix case falling through 2019-07-31 14:11:03 +00:00
778543c719 rust: Add a call to Rust test framework 2019-07-31 11:20:57 +00:00
18b8972029 bitflags: Use absolute imports
With relative import of the bitflags crate, the macros would try to fetch nonexistent paths, preventing tests form compiling.
2019-07-31 11:13:24 +00:00
fa31f8eee1 imservice: Check pointer validity 2019-07-31 10:43:39 +00:00
98a2e33d78 imservice: Use TryFrom for u32->enum conversions 2019-07-31 10:05:35 +00:00
58d01bf502 imservice: Use discriminants in enums 2019-07-31 10:05:35 +00:00
8326bd7016 rust: Create a root file for modules
The new `lib.rs` file is created to refer to all modules written in Rust. This way, only one `rustc` call is needed to compile an arbitrary amount of modules. It also converges with the way crates are structured.
2019-07-31 10:05:27 +00:00
d5f8b0d83b Merge branch 'simplify-rendering' into 'master'
Simplify layout and rendering

See merge request Librem5/squeekboard!102
2019-07-31 09:10:57 +00:00
e70a898af5 Merge branch 'adjust-keyboard-geometry' into 'master'
Adjust keyboard geometry

See merge request Librem5/squeekboard!103
2019-07-31 06:39:45 +00:00
df249646bc Merge branch 'update-numeric-keypad' into 'master'
Rename keypad-related files

See merge request Librem5/squeekboard!101
2019-07-31 06:37:09 +00:00
35ff93258e Adjust geometry to match the compact keyboard in places 2019-07-31 00:43:39 +02:00
c58d034494 Adjust bounds of the keyboard to better fit it in the available space 2019-07-31 00:43:36 +02:00
8f1de46381 Simplify layout and rendering
Remove pre-scaling of the bounds for the keyboard and its contents.
Calculate the scale factor based on the allocation and the desired width
and height of each keyboard, using the lower value of the horizontal and
vertical scale factors.
Apply scaling in the renderer and prepare to perform centering there.
2019-07-30 21:48:36 +00:00
1846a67e83 Merge branch 'readme' into 'master'
readme: Change the clone URL

Closes #30

See merge request Librem5/squeekboard!100
2019-07-30 20:39:09 +00:00
35ac14806c Rename keypad-related files 2019-07-30 20:47:29 +02:00
4aee4915d9 Merge branch 'generate-xkb-files' into 'master'
Generate XKB keymaps from XML instead of using pre-made ones

See merge request Librem5/squeekboard!90
2019-07-30 17:38:06 +00:00
5eeaa1c693 Remove unused geometry file 2019-07-30 19:28:16 +02:00
9b2fcf89e8 Use a test-oriented init call 2019-07-30 17:20:15 +02:00
e801a68f0d Add comments to explain what empty labels do 2019-07-30 16:50:23 +02:00
ffc5628637 readme: Change the clone URL 2019-07-30 13:08:12 +00:00
306aa89d06 Merge branch 'content_type' into 'master'
Finish up imservice state

See merge request Librem5/squeekboard!93
2019-07-30 11:44:19 +00:00
236415cde4 Merge branch 'add-landscape-orientation' into 'master'
Add landscape orientation

See merge request Librem5/squeekboard!99
2019-07-30 11:19:41 +00:00
d49e0eaa1b Center the keyboard in landscape orientation 2019-07-26 22:27:56 +00:00
107399a531 Don't set the geometry of the window in normal use
Setting the geometry prevents the widget from getting the correct
allocation and prevents us from positioning it correctly in
landscape mode.
2019-07-26 22:26:02 +00:00
99a7786dc3 Remove declaration of unused variable 2019-07-26 12:01:04 +02:00
d8f48cc48b Merge branch 'use-button-size-for-icons' into 'master'
Use the standard button size for icons

See merge request Librem5/squeekboard!98
2019-07-26 08:04:53 +00:00
2f0beb6d3a Add a simple test of keymap generation 2019-07-25 22:25:30 +02:00
3ab3627ffe Remove unused keymaps 2019-07-25 22:25:30 +02:00
70895999c2 Generate XKB keymaps from XML instead of using pre-made ones 2019-07-25 22:25:29 +02:00
ce311e1bf1 Use the standard button size for icons 2019-07-25 20:14:32 +00:00
e9cf572a3c Only recreate the widget when the keyboard layout changes
Avoid creating a widget before there is a window to put it in.
2019-07-25 18:07:29 +00:00
943b2ad9f3 Merge branch 'xkb_resource_oob_read' into 'master'
Fix out of bounds memory read in get_keymap_from_resource.

See merge request Librem5/squeekboard!97
2019-07-25 13:20:35 +00:00
f86bbb09f8 Fix out of bounds memory read in get_keymap_from_resource.
The function reads resource content into a buffer whose size matches the
size of the file contents. This buffer does not have an extra byte that
would 0 terminate this string. This is by itself is not a problem.
Unfortunately the buffer is passed to g_utf8_make_valid function with
size argument specified as -1 which means the buffer is supposed to be
NULL terminated. The end result is g_utf8_make_valid will read at least
1 byte past "contents" buffer size.

Fix this by specifying buffer size when calling g_utf8_make_valid.
2019-07-24 17:08:19 +02:00
1246776328 Create the keyboard surface every time it is needed
Icons are still blurry the first time the keyboard is shown after
rotation.
2019-07-24 14:04:28 +00:00
ea15f69e73 Render the keyboard to a subsurface of the widget 2019-07-24 13:12:57 +00:00
2e22bb5431 Merge branch 'fix-squeekboard-resources' into 'master'
Ensure that resources are built with the application

See merge request Librem5/squeekboard!95
2019-07-23 23:25:33 +00:00
a9a6e1d2b5 Ensure that resources are built with the application 2019-07-24 01:22:58 +02:00
7e939c36cc imservice: Call show/hide directly 2019-07-23 20:26:42 +00:00
c5d2d76ab1 imservice: Handle unavailable message 2019-07-23 20:26:42 +00:00
622ba6e38a imservice: Handle text change cause
Nothing is being done with this information yet
2019-07-23 20:26:42 +00:00
fad06348a7 imservice: Make imservice opaque
The structure is defined in Rust, with the intention of evaluating using Rust in this area. It's specifically not defined as repr(C), in order to encourage that. Without the repr, it was unsafe to have its members exposed in C.
2019-07-23 20:26:42 +00:00
a6ee303123 imservice: Handle content type in Rust
This adds `bitflags.rs` from the bitflags crate.
Due to not wanting to introduce Cargo as the dependency manager yet, it's slightly modified to compile as a naked module.
2019-07-23 20:25:13 +00:00
4b66add65f Merge branch 'ci' into 'master'
Run tests in ci

See merge request Librem5/squeekboard!94
2019-07-23 11:29:34 +00:00
79dce7c4c3 gitlab-ci: Run tests under xvfb
We create widgets so need a display.
2019-07-23 10:20:07 +02:00
aff71e0e33 debian: Add test run dependencies
We need xvfb to run the tests since this involves creating GTK
widgets.
2019-07-23 10:20:02 +02:00
9b10f56ba6 Keep the build directory as an artifact 2019-07-23 10:18:44 +02:00
2391947b34 Update CI configuration to enable tests 2019-07-23 10:18:44 +02:00
e903150971 Enable tests, fixing the existing ones to use the current API
This also involved building a static library for the application for
tests to link to. The main application executable also links to it.
2019-07-23 10:18:44 +02:00
7495ec9bbb Merge branch 'remove-includes' into 'master'
Remove unnecessary X11 includes

See merge request Librem5/squeekboard!91
2019-07-20 22:00:58 +00:00
e25d5a84b2 Remove unnecessary X11 includes 2019-07-20 23:57:38 +02:00
88ade4df1b Merge branch 'add-keyboards-for-purposes' into 'master'
Add keyboards for purposes

See merge request Librem5/squeekboard!89
2019-07-20 21:44:30 +00:00
00c3903672 Respond to the input purpose, showing a numeric keypad if requested 2019-07-20 17:33:55 +02:00
c801b17ba0 Add initial files to test specialized keyboard support 2019-07-20 17:33:50 +02:00
9ec8d62f3f Merge branch 'respond-to-input-source-changes' into 'master'
Respond to input source changes

See merge request Librem5/squeekboard!88
2019-07-20 15:31:40 +00:00
b1edcfcb1b Tidy up a merge 2019-07-20 17:26:00 +02:00
54b0f59935 Always create a new widget for a keyboard and update it if already visible 2019-07-20 17:25:55 +02:00
531b09f296 Merge branch 'adapt-keyboard-for-different-levels' into 'master'
Omit keys without labels on the current level, update key definitions

See merge request Librem5/squeekboard!87
2019-07-20 15:24:09 +00:00
e5b6d66d60 Omit keys without labels on the current level, update key definitions 2019-07-20 17:17:37 +02:00
a045810af6 Merge branch 'add-built-in-keymaps' into 'master'
Add built in keymaps

See merge request Librem5/squeekboard!78
2019-07-20 14:42:51 +00:00
d68a8fef9a Merge branch 'resize-icons' into 'master'
Declare the correct size for icons

See merge request Librem5/squeekboard!86
2019-07-20 14:41:29 +00:00
9162d4291f Declare the correct size for icons 2019-07-20 14:39:47 +00:00
93d7699aa7 Merge branch 'make-layout-more-flexible' into 'master'
Make layout handling more flexible

See merge request Librem5/squeekboard!85
2019-07-20 14:31:26 +00:00
6eb63f6a4c Refactor layout code, rescale and reformat when changing level 2019-07-19 17:35:49 +02:00
f6d4ca0387 Place keys after symbols have been read, skipping blank keys 2019-07-19 17:35:49 +02:00
7b41466a77 Start to refactor keyboard section layout 2019-07-19 17:35:49 +02:00
18c25084db Merge branch 'merge-renderers' into 'master'
Move EekGtkRenderer features into EekRenderer

Closes #61

See merge request Librem5/squeekboard!84
2019-07-19 14:56:54 +00:00
a5875402ef Move EekGtkRenderer features into EekRenderer 2019-07-18 15:42:27 +02:00
f3ed1ba247 Merge branch 'config' into 'master'
Clean up config.h (and some other stuff)

See merge request Librem5/squeekboard!83
2019-07-18 11:11:57 +00:00
633d69baca Drop HAVE_CLUTTER_GTK
We don't use it.
2019-07-17 19:50:53 +02:00
dbc8cc14bc Generate config.h
This allows us to remove a lot of #ifdef's. Either we want to use
a config.h or we don't. Since we'll want it for e.g. optional gsound
support later on let's have it.
2019-07-17 19:50:53 +02:00
c65583b911 Add a gitignore file
Based on the phosh one to ignore (upcoming) translations, editor
backup files and so forth.
2019-07-17 19:39:33 +02:00
3d518b5757 build: Bump meson dep since we use '/' 2019-07-17 19:37:05 +02:00
bfa72d7f61 Merge branch 'less-flicker' into 'master'
Make redisplaying the keyboard faster

Closes #60

See merge request Librem5/squeekboard!82
2019-07-17 16:32:29 +00:00
373713ba54 ServerContextService: Don't destroy widget all the time
This avoids icon theme lookups and lots of other stuff down the road.

Closes: #60
2019-07-17 17:16:35 +02:00
068c325ee2 EekGtkRenderer: Use a hash table for icon theme lookups 2019-07-17 17:14:42 +02:00
3b076e5e64 EekGtkRenderer: Simplify type declaration
It's 2019.
2019-07-17 17:14:42 +02:00
07d6e3a0f2 ServerContextService: Don't use gtk_widget_show_all
This gives children more flexibility without using `no_show_all`.
2019-07-17 17:14:42 +02:00
7690ef9a1a Merge branch 'layer-shell' into 'master'
Hide/show window instead of destroying it

Closes #42

See merge request Librem5/squeekboard!76
2019-07-17 11:34:10 +00:00
9974c385e5 EekboardContextService: Don't comment out property setters
This lets us keep the visible property up to date.
2019-07-17 00:44:09 +02:00
8dafad80b1 ServerContextService: Check for mapped/unmapped
Visible does not tell us if the widget is actually visible on the
screen.
2019-07-17 00:44:00 +02:00
93e9b2dde9 ServerContextService: Hide the widget instead of destroying it
This is quicker and makes sure we don't stack up surfaces.
2019-07-16 18:52:53 +02:00
c3a54595ea layersurface: Refresh layersurface on map
If the surface gets unmapped and mapped again we have another GDK window
so we have to reconfigure the layers surface on map and destroy it on
unmap.

This will be merged back into phosh if it works out.
2019-07-16 18:52:36 +02:00
95ef52fe42 ServerContextService: Remove more unused code
The whole visible/enable logic was disfunctional all the time.
What works is show_keyboard and hide_keyboard.
2019-07-16 18:47:55 +02:00
c638c40a09 ServerContextService: Drop everything depending on self->was_visible
This was never used so everything depending on it was dead code.
2019-07-16 18:47:55 +02:00
83d48d24ce ServerContextService: Really destroy the main window
Otherwise layer surfaces keep piling up
2019-07-16 18:47:55 +02:00
d807e43929 ServerContextService: Drop unneeded code
The layer shell code handles parts of this and others are just
not needed on wayland.
2019-07-16 18:47:55 +02:00
0a112be956 ServerContextService: Show keyboard when everything else is set up
This avoids some flickering.
2019-07-16 18:47:55 +02:00
078efa2a6e LayerShell: Set a proper namespace 2019-07-16 18:47:55 +02:00
5827827008 Update layer surface code from phosh
As of commit 77bba4fcb2d836a58ccf8913d9a514aac6cc49a2. This allows
us to split the widget creation from making it visible.
2019-07-16 18:47:55 +02:00
9c61d8de72 Merge branch 'dbus-prop' into 'master'
EekboardService: Properly toggle keyboard visibility on DBus

Closes #55

See merge request Librem5/squeekboard!80
2019-07-16 13:22:53 +00:00
f72ddc8129 Undo formatting changes 2019-07-16 14:06:49 +02:00
7e9c3b40bb Remove debugging code 2019-07-16 14:00:41 +02:00
a8371af9c0 Fall back to US layout and keymap if needed 2019-07-16 14:00:41 +02:00
4e11d071d9 Add a keymap for the US layout, update the US symbols 2019-07-16 14:00:41 +02:00
a7140705c4 Search for an xkb keymap in the resources 2019-07-16 14:00:41 +02:00
69986132b4 Use keysyms for the Shift modifier 2019-07-16 14:00:41 +02:00
3c97a3a592 Convert symbols file and update test keymap 2019-07-16 14:00:41 +02:00
268dda4da0 Improve symbol mapping 2019-07-16 14:00:41 +02:00
45f58a97b9 Update the test keymap 2019-07-16 14:00:41 +02:00
bdbbaf6099 Use groups to reference keysyms in the keymap 2019-07-16 14:00:41 +02:00
839968dc84 Try using a custom keymap 2019-07-16 14:00:41 +02:00
fbdc5f4a93 Stash for sharing 2019-07-16 14:00:41 +02:00
e5648a82a3 Remove explicit keycodes in XML, auto-generate them instead
This makes it easier to keep the geometry and symbols files in sync.
2019-07-16 14:00:41 +02:00
38133d326b Merge branch 'autogen.sh' into 'master'
Remove more files

See merge request Librem5/squeekboard!81
2019-07-16 11:06:55 +00:00
cc00fcb5c9 Remove more files
autogen.sh is for automake and the TODO refers to eekboard.
2019-07-16 11:00:59 +02:00
53f7a14717 EekboardService: Properly toggle keyboard visibility on DBus
Closes: #55
2019-07-16 10:21:59 +02:00
922495ca06 Merge branch 'remove-unused-files' into 'master'
Remove unused files and functions

See merge request Librem5/squeekboard!79
2019-07-16 07:16:29 +00:00
e5e2e08ff4 Merge branch 'fewer-redraws' into 'master'
keyboard: Schedule widget redraw instead of gdk_window_invalidate_rect

See merge request Librem5/squeekboard!75
2019-07-15 22:57:12 +00:00
c7c410210b Merge branch 'scale' into 'master'
Honor widget scale  factor

See merge request Librem5/squeekboard!56
2019-07-15 22:27:34 +00:00
cb7c214aa0 Merge branch 'fixes' into 'master'
Fixes

See merge request Librem5/squeekboard!74
2019-07-15 22:20:40 +00:00
6f5f49729c Remove unused files and functions 2019-07-15 23:45:17 +02:00
94c9442de1 keyboard: Drop now unused clip_bounds_to_dirty_rectangle() 2019-07-15 17:42:32 +02:00
8c044d0852 keyboard: Schedule widget redraw instead of gdk_window_invalidate_rect
The later would invaliate the drawn area again and again in a ::draw()
handler. This caused infinite redraws when e.g. a key was locked.  To
reproduce break e.g. on `eek_gtk_keyboard_real_draw()` and see how it is
invoked again and again.
2019-07-15 17:42:32 +02:00
1f0cc0a5f3 keyboard: Don't leak on set_keyboard()
Unref and disconnect signals before setting a new keyboard.
2019-07-15 14:12:10 +02:00
5693ce3df7 keyboard: Simplify signal disconnect
We're only keeping the signal ids around for disconnect but that only
happens in dispose so it's o.k.to just disconnect all keyboard signals
we listen to.
2019-07-15 14:12:10 +02:00
bcf04ab11e Merge branch 'exclusive-zone' into 'master'
LayerSurface: Make exclusive zone identical to height

Closes #53

See merge request Librem5/squeekboard!72
2019-07-15 11:55:41 +00:00
086f6bd772 renderer: Only scale by output scale
The original eekboard code scaled icons by a factor. That was simplified
in c529e9ed9c but we can do away with it
completely and fetch the icons at the right size making them not blurry.
2019-07-15 13:23:16 +02:00
d0fa444a0e Honor the outputs scale factor 2019-07-15 13:13:34 +02:00
cd81aeb286 get_icon_surface: Add a scale argument
This will allow us to pass the output scale around
2019-07-15 13:13:34 +02:00
7db33bc92e renderer: Add icons in resource bundle to the icon theme 2019-07-15 13:13:34 +02:00
fb6c501e44 renderer: Use gtk_icon_theme_load_surface
This will allow us to feed in the output scale.
2019-07-15 13:12:26 +02:00
ce7b398f7b LayerSurface: Make exclusive zone identical to height
Othewise we hide content beneath the keyboard.

Closes: #53
2019-07-15 12:49:11 +02:00
4d8d3a8109 Merge branch 'suppress-warnings' into 'master'
Suppress warning message

See merge request Librem5/squeekboard!70
2019-07-13 22:14:54 +00:00
a183cf8b63 Suppress warning message 2019-07-14 00:13:41 +02:00
f834edcf94 Merge branch 'fix-compiler-warnings' into 'master'
Fix use of inappropriate type

See merge request Librem5/squeekboard!69
2019-07-13 19:47:40 +00:00
17802a9408 Fix use of inappropriate type 2019-07-13 18:36:59 +02:00
ac1aad881c Merge branch '49-inconsistent-behaviour-of-shift-key-s-pressed-state' into 'master'
Resolve "Inconsistent behaviour of shift key's pressed state"

Closes #49

See merge request Librem5/squeekboard!66
2019-07-13 16:35:07 +00:00
928110a92d Merge branch 'add-missing-icon' into 'master'
Add keyboard preferences icon

See merge request Librem5/squeekboard!68
2019-07-12 21:09:49 +00:00
f6479fafe2 Add keyboard preferences icon 2019-07-12 23:07:01 +02:00
62b1c2ba84 Revert to latch behavior for letters 2019-07-12 19:54:21 +00:00
c0ac5e540f Merge branch 'add-key-icons' into 'master'
Add key icons

Closes #44

See merge request Librem5/squeekboard!65
2019-07-12 19:17:29 +00:00
fb5ec5557b Make icons smaller 2019-07-12 20:12:09 +02:00
74d94e6792 Merge branch 'remove-unused-xml' into 'master'
Remove unused XML from the US definitions

See merge request Librem5/squeekboard!64
2019-07-12 18:08:55 +00:00
63f4c6b4da Use icons for Shift and Return in the US layout 2019-07-12 20:04:50 +02:00
2774c1c988 Try to load icons from app resources first 2019-07-12 20:04:22 +02:00
469b0c0a9a Add icons to the resource manifest 2019-07-12 20:04:02 +02:00
2ddd217737 Add Enter and Shift icons 2019-07-12 19:16:21 +02:00
c4e8e34ad6 Remove unused XML from the US definitions 2019-07-12 17:15:38 +00:00
4dc18c0af4 Merge branch '27-period-should-not-change-when-caps-lock-is-active' into 'master'
Resolve "Period should not change when caps lock is active"

Closes #27

See merge request Librem5/squeekboard!63
2019-07-12 17:11:10 +00:00
55c6911b87 Remove level with > character from . key 2019-07-12 17:17:11 +02:00
9bf0da5409 Merge branch 'adjust-scaling' into 'master'
Reduce icon size to match platform guidelines

See merge request Librem5/squeekboard!62
2019-07-12 15:15:43 +00:00
7d5b2dd1de Reduce icon size to match platform guidelines 2019-07-12 16:10:31 +02:00
6091632e40 Merge branch 'simplify-geometry-xml' into 'master'
Simplify geometry XML

See merge request Librem5/squeekboard!61
2019-07-12 14:09:57 +00:00
44110fd4d9 Remove bounds for everything except the geometry element 2019-07-12 14:00:20 +00:00
74d76ebfeb Remove unused XML elements 2019-07-12 14:00:20 +00:00
760bc138b0 Test effect of setting attributes to zero 2019-07-12 14:00:20 +00:00
2a4763d4f3 Merge branch 'fix-bottom-margin' into 'master'
Include extra space in the window object

Closes #47

See merge request Librem5/squeekboard!60
2019-07-12 13:42:20 +00:00
4b92f205ef Include extra space in the window object 2019-07-12 10:30:44 +00:00
a5668fa1db Merge branch 'remove-pressed-key-popups' into 'master'
Remove pop-ups for pressed keys

See merge request Librem5/squeekboard!59
2019-07-11 23:42:34 +00:00
de39256377 Remove pop-ups for pressed keys 2019-07-11 23:39:33 +00:00
f53709c83d Merge branch 'fix-bottom-margin' into 'master'
Fix clipping issue at bottom of keyboard

Closes #47

See merge request Librem5/squeekboard!58
2019-07-11 23:07:01 +00:00
8ad0192e55 Fix clipping issue at bottom of keyboard
Closes #47.
2019-07-11 23:04:29 +00:00
791e454cb6 Merge branch 'functioning-views' into 'master'
Basic functioning views

See merge request Librem5/squeekboard!57
2019-07-11 22:58:50 +00:00
c85638be4d Use a dummy, non-emitting key to switch views 2019-07-11 19:38:02 +00:00
a61b1fdf06 Merge branch 'implement-more-view-behavior' into 'master'
Improve view behavior to more closely reflect #38

See merge request Librem5/squeekboard!55
2019-07-11 16:29:26 +00:00
07c25d1d91 Improve view behavior to more closely reflect #38 2019-07-11 16:29:26 +00:00
83dafd87a4 Merge branch 'copyright' into 'master'
Copyright

See merge request Librem5/squeekboard!6
2019-07-11 13:49:00 +00:00
25a8733957 Merge branch 'scale' into 'master'
Simplify icon rendering a bit

See merge request Librem5/squeekboard!52
2019-07-11 13:42:50 +00:00
c529e9ed9c render: Simplify drawing
Instead of doing scale guessing we know that we get a properly
sized image from GTK+ so just scale it down a bit so it gets
some border within the drawing area.
2019-07-11 15:40:18 +02:00
d6a8a85b5e render: Get foreground color only once 2019-07-11 15:40:18 +02:00
3a945535f7 render: Remove trailing white space 2019-07-11 15:40:18 +02:00
0fc4374193 gtk-renderer: Simplify 2019-07-11 15:40:18 +02:00
e350b4ab92 Merge branch 'some-bugfixes' into 'master'
MERGE these: Some bugfixes - the buildsystem is acting up again

See merge request Librem5/squeekboard!53
2019-07-11 13:39:56 +00:00
626527ee09 Merge branch 'feature-xml-resources' into 'master'
FINAL: bundle xml resources, allows running uninstalled from git repo

Closes #29 and #21

See merge request Librem5/squeekboard!49
2019-07-11 13:33:45 +00:00
c4a462c385 Merge branch 'ci' into 'master'
gitlab-ci: No need for our ci repository

See merge request Librem5/squeekboard!54
2019-07-11 13:16:32 +00:00
706a04dbfc gitlab-ci: No need for our ci repository
Just using debian buster makes things more stable.
2019-07-11 14:31:25 +02:00
7fd51af4de debian: Drop virtboard build-dependency 2019-07-11 14:31:25 +02:00
c1af9b2ba4 Add dbus protocol definition
This let's us drop the virtboard build dependency.
2019-07-11 14:31:25 +02:00
5efb4cc58d Bundle keyboard definitions
This allows running uninstalled from a git repo

Closes: #21, #29
2019-07-11 13:40:03 +02:00
4b2977d601 Plug 3 leaks 2019-07-11 13:26:04 +02:00
2f1c1c2fb1 Remove unused variable and remove damage from botched rebase
- remove bounds it is not used.

- remove the g_clear_pointer, it does the same thing as the if-block
  above, the were both there as the result of the merge, and it is
  apparently easily overlooked

- cleanup after myself (FIXMEs)
2019-07-11 13:24:48 +02:00
f47ef09a1f Merge branch 'implement-basic-views' into 'master'
Implement basic keyboard views

See merge request Librem5/squeekboard!51
2019-07-11 10:24:29 +00:00
47041b0fac Implement basic keyboard views
Use existing concepts of levels and modifier latches and locks to
implement the three view design of issue #38.

The use of a lock to switch from letter to numbers and a latch to
handle upper and lower case has side effects, but these can be
addressed in a future commit.
2019-07-10 23:33:45 +00:00
b6111b5e00 Merge branch 'fix-backspace-key' into 'master'
Specify a keyval to make the backspace key work again

Closes #45

See merge request Librem5/squeekboard!50
2019-07-10 23:12:59 +00:00
b8a2b2d7c8 Specify a keyval to make the backspace key work again 2019-07-11 01:09:04 +02:00
0765ea1b86 Merge branch 'update-symbols' into 'master'
Update symbols to more closely resemble #38

See merge request Librem5/squeekboard!48
2019-07-10 22:20:30 +00:00
64223704e0 Update symbols to more closely resemble #38 2019-07-10 23:50:34 +02:00
8c14763ea4 Merge branch 'theme-path' into 'master'
Drop now unused theme_path

See merge request Librem5/squeekboard!46
2019-07-10 17:09:58 +00:00
10cd93022a Merge branch 'update-icons' into 'master'
Use an icon for backspace

See merge request Librem5/squeekboard!47
2019-07-10 16:57:09 +00:00
d006aede6a Merge branch 'top-margin' into 'master'
Add some border at the top

Closes #28

See merge request Librem5/squeekboard!43
2019-07-10 15:46:16 +00:00
b57e1ce660 Drop now unused theme_path 2019-07-10 15:39:16 +02:00
1b59c4dad3 Use an icon for backspace 2019-07-10 14:36:19 +02:00
189c721d7e Merge branch 'use_gresource' into 'master'
Use a gresource to store the css

See merge request Librem5/squeekboard!28
2019-07-10 11:36:53 +00:00
1ff1592f24 Merge branch 'master' into 'use_gresource'
# Conflicts:
#   src/server-context-service.c
2019-07-10 11:35:40 +00:00
7f5f310bf0 Add some border at the top
Closes: #28
2019-07-10 11:31:24 +02:00
f999861228 Merge branch 'remove-more-unused-code-and-data' into 'master'
Remove unused color definitions

See merge request Librem5/squeekboard!42
2019-07-09 21:40:36 +00:00
a571bd7dca Remove unused color definitions 2019-07-09 17:55:40 +02:00
3d0d28fa01 Merge branch 'remove-unused-eekboard-context-service-code' into 'master'
Remove currently unused eekboard code

See merge request Librem5/squeekboard!41
2019-07-09 15:48:59 +00:00
4c54b49ef5 Merge branch 'remove-unused-sources' into 'master'
Remove unlisted files

See merge request Librem5/squeekboard!38
2019-07-09 14:44:00 +00:00
eb940bcf52 Remove currently unused eekboard code 2019-07-09 16:34:16 +02:00
be0e773879 Merge branch 'quick-review-fast-lane-very-speedy' into 'master'
Some cleanups, and some FIXME hints for future work (no functional changes)

See merge request Librem5/squeekboard!39
2019-07-09 14:25:45 +00:00
056e07e80e Merge branch 'prevent-warnings' into 'master'
Prevent compiler warnings by commenting out unused code

See merge request Librem5/squeekboard!37
2019-07-09 13:44:54 +00:00
83b36d07d0 Add note about unused code 2019-07-09 15:28:02 +02:00
89aaf05aff Some minor cleanups 2019-07-09 13:52:23 +02:00
2f87fd46fb Improve codeflow 2019-07-09 13:50:14 +02:00
e04276ee38 Use properly typed and named variables for user_data 2019-07-09 13:46:44 +02:00
05c3061f08 Add some FIXME hints for future work 2019-07-09 13:41:20 +02:00
c33006bcbc use g_clear_pointer with gtk_widget_destroy
brief, clear, idiomatic and grep friendly
2019-07-09 13:33:49 +02:00
4bf4500ae1 Remove unlisted files 2019-07-09 01:07:19 +02:00
e2944ff4a7 Use a macro to declare a type with private data 2019-07-09 00:46:03 +02:00
f79b5dadbb Use a macro to declare a type with private data 2019-07-09 00:41:25 +02:00
4d44129b04 Prevent compiler warnings by commenting out unused code 2019-07-09 00:24:57 +02:00
b3e1d84e6c Merge branch 'mem' into 'master'
Fix visibility-related bugs

See merge request Librem5/squeekboard!25
2019-07-08 21:25:27 +00:00
6702edaa9d Merge branch 'fix-deprecated-warnings' into 'master'
Fix deprecated warnings

See merge request Librem5/squeekboard!34
2019-07-08 21:19:57 +00:00
a3a6e5933a Merge branch 'quick-review-fast-lane-very-speedy' into 'master'
Quick review fast lane very speedy

See merge request Librem5/squeekboard!36
2019-07-08 21:01:40 +00:00
66ec95ebb0 fix-up prototypes (-Wincompatible-pointer-types) 2019-07-08 09:21:26 +02:00
a944bf85b8 remove stray const (-Wdiscarded-qualifiers) 2019-07-08 09:20:17 +02:00
1d1829f664 fix accidentally committed line (-Wincompatible-pointer-types) 2019-07-08 09:18:41 +02:00
094aa872ce Cleanups: fix deprecated g_type_class_add_private()
- use G_DECLARE_ and G_DEFINE_ macros
- move all data into ClassNamePrivate
- use _get_instance_private()

This should not introduce any functional changes or breakage.

Skipped two classes (EekKeyboard and EekboardContextService) for now in
order not to break the build.

These two classes are used in some very funky WIP code that tries to
circumvent encapsulation.

(Funky code is in eekboard/key-emitter.c and eekboard/eekboard-context-service.c)
2019-07-08 08:44:05 +02:00
eaf925e30b Cleanups: fix g_type_init() deprecation warning
None of this seems necessary anymore. This file could be axed, but leave
it for now.
2019-07-08 08:39:43 +02:00
722d3d1ad4 Cleanups: fix deprecations
gtk_widget_get_root_window()
	gdk_screen_get_monitor_at_window()
	gdk_screen_get_monitor_geometry()
2019-07-08 08:39:16 +02:00
b69b3e9409 Merge branch 'fix-uninitialized-var' into 'master'
Fix an uninitialized-variable warning, and fixes gradients (quickie)

See merge request Librem5/squeekboard!35
2019-07-07 17:37:11 +00:00
ae5eaeec93 Fix an uninitialized-variable warning, and fixes gradients 2019-07-07 18:45:56 +02:00
c393eb20be Merge branch 'improve-key-rendering' into 'master'
Improve key rendering and eliminate two deprecation warnings

See merge request Librem5/squeekboard!33
2019-07-07 11:39:12 +00:00
0e8715b4ff Improve key rendering and eliminate two deprecation warnings
- Replace two calls to deprecated gdk_cairo_create()

- Alleviate asymmetry between rendering pressed and released keys
  by consistenly clipping the same area up front to avoid
  artefacts

- make sure pressed and released keys are shown immediately by
  calling gdk_window_invalidate_rect()

- improve consistency between render_(pressed|locked|released)_key

- improve code flow
2019-07-07 11:34:24 +02:00
abf8f4daa8 eek-theme: Remove code for old croko versions
These versions aren't even in Debian's oldstable release.
2019-07-04 16:21:18 +02:00
aba242301d Use a gresource to store the css
This makes build / test faster since one can skip install. It's
also more obvious which file is being used.
2019-07-04 16:16:04 +02:00
c3ffe6ab8b visibility: Handle visibility change no-ops 2019-07-04 08:48:43 +00:00
3d1133cdb5 Fix memory corruption due to a wrong assumption 2019-07-04 07:48:46 +00:00
47026b669b Make copyright more granular 2019-06-29 10:50:30 +00:00
109 changed files with 4632 additions and 8856 deletions

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
.zanata-cache/
_build
TAGS
tags
vgdump
*.swp
*~
\#*#
.\#*

View File

@ -2,20 +2,30 @@ image: debian:buster
stages: stages:
- build - build
- test
.tags: &tags
tags:
- librem5
before_script: before_script:
- apt-get -y update
- apt-get -y install wget gnupg2
- echo "deb http://ci.puri.sm/ scratch librem5" > /etc/apt/sources.list.d/ci.list
- wget -O- https://ci.puri.sm/ci-repo.key | apt-key add -
- apt-get -y update - apt-get -y update
- apt-get -y build-dep . - apt-get -y build-dep .
build_meson: build_meson:
<<: *tags
stage: build stage: build
tags: artifacts:
- librem5 paths:
- _build
script: script:
- meson . _build/ -Ddepdatadir=/usr/share - meson . _build/ -Ddepdatadir=/usr/share
- ninja -C _build install - ninja -C _build install
test:
<<: *tags
stage: test
dependencies:
- build_meson
script:
- xvfb-run -s -noreset ninja -C _build test

View File

@ -33,8 +33,8 @@ See `.gitlab-ci.yml`.
### Build from git repo ### Build from git repo
``` ```
$ git clone https://source.puri.sm/Librem5/eekboard.git $ git clone https://source.puri.sm/Librem5/squeekboard.git
$ cd eekboard $ cd squeekboard
$ mkdir ../build $ mkdir ../build
$ meson ../build/ $ meson ../build/
$ cd ../build $ cd ../build

1
TODO
View File

@ -1 +0,0 @@
See https://github.com/ueno/eekboard/wiki/TODO

View File

@ -1,20 +0,0 @@
#!/bin/sh
# Run this to generate all the initial makefiles, etc.
srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.
PKG_NAME="eekboard"
(test -f $srcdir/configure.ac \
&& test -f $srcdir/README.md ) || {
echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
echo " top-level $PKG_NAME directory"
exit 1
}
ACLOCAL_FLAGS="$ACLOCAL_FLAGS -I m4"
REQUIRED_AUTOMAKE_VERSION=1.10
REQUIRED_AUTOCONF_VERSION=2.60
. gnome-autogen.sh

View File

@ -0,0 +1,20 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
<interface name="sm.puri.OSK0">
<method name="SetVisible">
<arg name="visible" type="b" direction="in"/>
<doc:doc><doc:description>
Switch keyboard visibility
</doc:description></doc:doc>
</method>
<method name="GetVisible">
<arg name="visible" type="b" direction="out"/>
<doc:doc><doc:description>
Get keyboard visibility
</doc:description></doc:doc>
</method>
<property name="Visible" type="b" access="read">
</property>
</interface>
</node>

10
data/icons/key-enter.svg Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16"
version="1.1" viewBox="0 0 24 24">
<path d="M 24,1 L 24,10 C 24,15 20,17 17,17 L 7,17 L 10,20 L 10,23
L 7,23 L 0,15 L 7,7 L 10,7 L 10,10 L 7,13 L 17,13
C 19,13 20,12 20,10 L 20,1 Z"
stroke="none" fill="black" />
</svg>

After

Width:  |  Height:  |  Size: 388 B

8
data/icons/key-shift.svg Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16"
version="1.1" viewBox="0 0 24 24">
<path d="M 12,2 L 22,14 L 16,14 L 16,22 L 8,22 L 8,14 L 2,14 Z"
stroke="none" fill="black" />
</svg>

After

Width:  |  Height:  |  Size: 279 B

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
id="svg4043"
version="1.1"
viewBox="0 0 4.2333331 4.2333093"
height="4.2333093mm"
width="4.2333331mm">
<defs
id="defs4037" />
<metadata
id="metadata4040">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(-86.329776,-68.097636)"
id="layer1">
<g
style="stroke-width:1.00004983;fill:#2e3436;fill-opacity:1"
transform="matrix(0.99990029,0,0,1,-7.1823833,-1.8799927)"
id="g842">
<g
style="stroke-width:1.00004983;fill:#2e3436;fill-opacity:1"
id="g836">
<path
id="path5166"
d="m 95.636719,69.978516 c -1.165869,0 -2.115235,0.949365 -2.115235,2.115234 0,1.165869 0.949366,2.117188 2.115235,2.117188 1.165869,0 2.117187,-0.951319 2.117187,-2.117188 0,-1.165869 -0.951318,-2.115234 -2.117187,-2.115234 z m 0,0.529296 c 0.879886,0 1.58789,0.706052 1.58789,1.585938 0,0.879886 -0.708004,1.587891 -1.58789,1.587891 -0.879886,0 -1.585938,-0.708005 -1.585938,-1.587891 0,-0.879886 0.706052,-1.585937 1.585938,-1.585938 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52919304;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.26459652;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 95.636719,70.109375 c -0.144398,0 -0.27248,0.07793 -0.373047,0.189453 -0.100567,0.111521 -0.18209,0.261405 -0.25,0.439453 -0.135821,0.356096 -0.214844,0.830395 -0.214844,1.355469 0,0.525074 0.07902,1.001326 0.214844,1.357422 0.06791,0.178048 0.149433,0.327932 0.25,0.439453 0.100567,0.111521 0.228649,0.1875 0.373047,0.1875 0.144397,0 0.27248,-0.07598 0.373047,-0.1875 0.100566,-0.111521 0.182089,-0.261405 0.25,-0.439453 0.135821,-0.356096 0.216797,-0.832348 0.216796,-1.357422 0,-0.525074 -0.08097,-0.999373 -0.216796,-1.355469 -0.06791,-0.178048 -0.149434,-0.327932 -0.25,-0.439453 -0.100567,-0.111521 -0.22865,-0.189453 -0.373047,-0.189453 z m 0,0.265625 c 0.05067,0 0.109272,0.02564 0.177734,0.101562 0.06846,0.07592 0.139293,0.198356 0.199219,0.355469 0.119851,0.314227 0.197266,0.763915 0.197266,1.261719 0,0.497804 -0.07742,0.949446 -0.197266,1.263672 -0.05993,0.157113 -0.130756,0.279549 -0.199219,0.355469 -0.06846,0.07592 -0.12706,0.101562 -0.177734,0.101562 -0.05067,0 -0.107319,-0.02564 -0.175781,-0.101562 -0.06846,-0.07592 -0.139294,-0.198356 -0.199219,-0.355469 C 95.141867,73.043196 95.0625,72.591554 95.0625,72.09375 c 0,-0.497804 0.07937,-0.947492 0.199219,-1.261719 0.05993,-0.157113 0.130756,-0.279549 0.199219,-0.355469 C 95.5294,70.400643 95.586045,70.375 95.636719,70.375 Z"
id="circle5168" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.26459652;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 93.697266,71.962891 v 0.263671 h 3.96875 v -0.263671 z"
id="path5170" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@ -1,189 +1,120 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<geometry version="0.90"> <geometry version="0.90">
<bounds x="0.000000" y="0.000000" width="426.0000" height="296.5853"/> <bounds x="10" y="10" width="410.0000" height="229"/>
<section angle="0"> <section angle="0">
<bounds x="0" y="0" width="608.7804" height="201.3658"/>
<row orientation="1"> <row orientation="1">
<key keycode="24" name="AD01" oref="outline2"> <key name="AD01" oref="outline2" />
<bounds x="65.56097" y="42.14634" width="37.46341" height="52.44877"/> <key name="AD02" oref="outline2" />
</key> <key name="AD03" oref="outline2" />
<key keycode="25" name="AD02" oref="outline2"> <key name="AD04" oref="outline2" />
<bounds x="106.1463" y="42.14634" width="37.46341" height="37.46341"/> <key name="AD05" oref="outline2" />
</key> <key name="AD06" oref="outline2" />
<key keycode="26" name="AD03" oref="outline2"> <key name="AD07" oref="outline2" />
<bounds x="145.1707" y="42.14634" width="37.46341" height="37.46341"/> <key name="AD08" oref="outline2" />
</key> <key name="AD09" oref="outline2" />
<key keycode="27" name="AD04" oref="outline2"> <key name="AD10" oref="outline2" />
<bounds x="185.7560" y="42.14634" width="37.46341" height="37.46341"/>
</key>
<key keycode="28" name="AD05" oref="outline2">
<bounds x="226.3414" y="42.14634" width="37.46341" height="37.46341"/>
</key>
<key keycode="29" name="AD06" oref="outline2">
<bounds x="266.9268" y="42.14634" width="37.46341" height="37.46341"/>
</key>
<key keycode="30" name="AD07" oref="outline2">
<bounds x="307.5121" y="42.14634" width="37.46341" height="37.46341"/>
</key>
<key keycode="31" name="AD08" oref="outline2">
<bounds x="348.0975" y="42.14634" width="37.46341" height="37.46341"/>
</key>
<key keycode="32" name="AD09" oref="outline2">
<bounds x="388.6829" y="42.14634" width="37.46341" height="37.46341"/>
</key>
<key keycode="33" name="AD10" oref="outline2">
<bounds x="429.2682" y="42.14634" width="37.46341" height="37.46341"/>
</key>
</row> </row>
</section> </section>
<section angle="0"> <section angle="0">
<bounds x="0" y="0" width="608.7804" height="201.3658"/>
<row orientation="1"> <row orientation="1">
<key keycode="38" name="AC01" oref="outline2"> <key name="AC01" oref="outline2" />
<bounds x="76.48780" y="82.73170" width="37.46341" height="37.46341"/> <key name="AC02" oref="outline2" />
</key> <key name="AC03" oref="outline2" />
<key keycode="39" name="AC02" oref="outline2"> <key name="AC04" oref="outline2" />
<bounds x="115.5121" y="82.73170" width="37.46341" height="37.46341"/> <key name="AC05" oref="outline2" />
</key> <key name="AC06" oref="outline2" />
<key keycode="40" name="AC03" oref="outline2"> <key name="AC07" oref="outline2" />
<bounds x="156.0975" y="82.73170" width="37.46341" height="37.46341"/> <key name="AC08" oref="outline2" />
</key> <key name="AC09" oref="outline2" />
<key keycode="41" name="AC04" oref="outline2"> <key name="AC10" oref="outline2" />
<bounds x="196.6829" y="82.73170" width="37.46341" height="37.46341"/>
</key>
<key keycode="42" name="AC05" oref="outline2">
<bounds x="237.2682" y="82.73170" width="37.46341" height="37.46341"/>
</key>
<key keycode="43" name="AC06" oref="outline2">
<bounds x="277.8536" y="82.73170" width="37.46341" height="37.46341"/>
</key>
<key keycode="44" name="AC07" oref="outline2">
<bounds x="318.4390" y="82.73170" width="37.46341" height="37.46341"/>
</key>
<key keycode="45" name="AC08" oref="outline2">
<bounds x="359.0243" y="82.73170" width="37.46341" height="37.46341"/>
</key>
<key keycode="46" name="AC09" oref="outline2">
<bounds x="399.6097" y="82.73170" width="37.46341" height="37.46341"/>
</key>
</row> </row>
</section> </section>
<section angle="0"> <section angle="0">
<bounds x="0" y="0" width="608.7804" height="201.3658"/>
<row orientation="1"> <row orientation="1">
<key keycode="50" name="LFSH" oref="altline"> <key name="LFSH" oref="altline" />
<bounds x="3.121951" y="121.7560" width="88.97561" height="37.46341"/> <key name="AB01" oref="outline2" />
</key> <key name="AB02" oref="outline2" />
<key keycode="52" name="AB01" oref="outline2"> <key name="AB03" oref="outline2" />
<bounds x="95.21951" y="121.7560" width="37.46341" height="37.46341"/> <key name="AB04" oref="outline2" />
</key> <key name="AB05" oref="outline2" />
<key keycode="53" name="AB02" oref="outline2"> <key name="AB06" oref="outline2" />
<bounds x="135.8048" y="121.7560" width="37.46341" height="37.46341"/> <key name="AB07" oref="outline2" />
</key> <key name="BKSP" oref="altline" />
<key keycode="54" name="AB03" oref="outline2">
<bounds x="176.3902" y="121.7560" width="37.46341" height="37.46341"/>
</key>
<key keycode="55" name="AB04" oref="outline2">
<bounds x="215.4146" y="121.7560" width="37.46341" height="37.46341"/>
</key>
<key keycode="56" name="AB05" oref="outline2">
<bounds x="256.0000" y="121.7560" width="37.46341" height="37.46341"/>
</key>
<key keycode="57" name="AB06" oref="outline2">
<bounds x="296.5853" y="121.7560" width="37.46341" height="37.46341"/>
</key>
<key keycode="58" name="AB07" oref="outline2">
<bounds x="337.1707" y="121.7560" width="37.46341" height="37.46341"/>
</key>
<key keycode="22" name="BKSP" oref="altline">
<bounds x="529.1707" y="1.560976" width="79.60975" height="37.46341"/>
</key>
</row> </row>
</section> </section>
<section angle="0"> <section angle="0">
<bounds x="0" y="0" width="608.7804" height="201.3658"/>
<row orientation="1"> <row orientation="1">
<key keycode="37" name="LCTL" oref="altline"> <key keycode="0" name="ABC123" oref="altline" />
<bounds x="62.43902" y="162.3414" width="48.39024" height="37.46341"/> <key name="I149" oref="altline" />
</key> <key name="SPCE" oref="spaceline" />
<key keycode="66" name="ALTGR" oref="altline"> <key name="AB08" oref="outline2" />
<bounds x="113.9512" y="162.3414" width="48.39024" height="37.46341"/> <key name="RTRN" oref="outline7" />
</key>
<key keycode="65" name="SPCE" oref="spaceline">
<bounds x="165.4634" y="162.3414" width="217.5853" height="37.46341"/>
</key>
<key keycode="60" name="AB09" oref="outline2">
<bounds x="418.3414" y="121.7560" width="37.46341" height="37.46341"/>
</key>
<key keycode="36" name="RTRN" oref="outline7">
<bounds x="519.8048" y="82.73170" width="88.97561" height="37.46341"/>
</key>
</row> </row>
</section> </section>
<outline id="outline2" corner-radius="1.000000"> <outline id="outline2" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/> <point x="0.000000" y="0.000000"/>
<point x="37.46341" y="0.000000"/> <point x="37.46341" y="0.000000"/>
<point x="37.46341" y="52.44877"/> <point x="37.46341" y="52"/>
<point x="0.000000" y="52.44877"/> <point x="0.000000" y="52"/>
</outline> </outline>
<outline id="altline" corner-radius="1.000000"> <outline id="altline" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/> <point x="0.000000" y="0.000000"/>
<point x="48.39024" y="0.000000"/> <point x="48.39024" y="0.000000"/>
<point x="48.39024" y="52.44877"/> <point x="48.39024" y="52"/>
<point x="0.000000" y="52.44877"/> <point x="0.000000" y="52"/>
</outline> </outline>
<outline id="outline4" corner-radius="1.000000"> <outline id="outline4" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/> <point x="0.000000" y="0.000000"/>
<point x="59.31707" y="0.000000"/> <point x="59.31707" y="0.000000"/>
<point x="59.31707" y="52.44877"/> <point x="59.31707" y="52"/>
<point x="0.000000" y="52.44877"/> <point x="0.000000" y="52"/>
</outline> </outline>
<outline id="outline5" corner-radius="1.000000"> <outline id="outline5" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/> <point x="0.000000" y="0.000000"/>
<point x="59.31707" y="0.000000"/> <point x="59.31707" y="0.000000"/>
<point x="59.31707" y="52.44877"/> <point x="59.31707" y="52"/>
<point x="0.000000" y="52.44877"/> <point x="0.000000" y="52"/>
</outline> </outline>
<outline id="outline6" corner-radius="1.000000"> <outline id="outline6" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/> <point x="0.000000" y="0.000000"/>
<point x="68.68292" y="0.000000"/> <point x="68.68292" y="0.000000"/>
<point x="68.68292" y="52.44877"/> <point x="68.68292" y="52"/>
<point x="0.000000" y="52.44877"/> <point x="0.000000" y="52"/>
</outline> </outline>
<outline id="outline7" corner-radius="1.000000"> <outline id="outline7" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/> <point x="0.000000" y="0.000000"/>
<point x="88.97561" y="0.000000"/> <point x="88.97561" y="0.000000"/>
<point x="88.97561" y="52.44877"/> <point x="88.97561" y="52"/>
<point x="0.000000" y="52.44877"/> <point x="0.000000" y="52"/>
</outline> </outline>
<outline id="outline8" corner-radius="1.000000"> <outline id="outline8" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/> <point x="0.000000" y="0.000000"/>
<point x="88.97561" y="0.000000"/> <point x="88.97561" y="0.000000"/>
<point x="88.97561" y="52.44877"/> <point x="88.97561" y="52"/>
<point x="0.000000" y="52.44877"/> <point x="0.000000" y="52"/>
</outline> </outline>
<outline id="outline9" corner-radius="1.000000"> <outline id="outline9" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/> <point x="0.000000" y="0.000000"/>
<point x="109.2682" y="0.000000"/> <point x="109.2682" y="0.000000"/>
<point x="109.2682" y="52.44877"/> <point x="109.2682" y="52"/>
<point x="0.000000" y="52.44877"/> <point x="0.000000" y="52"/>
</outline> </outline>
<outline id="outline10" corner-radius="1.000000"> <outline id="outline10" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/> <point x="0.000000" y="0.000000"/>
<point x="37.46341" y="0.000000"/> <point x="37.46341" y="0.000000"/>
<point x="37.46341" y="52.44877"/> <point x="37.46341" y="52"/>
<point x="0.000000" y="52.44877"/> <point x="0.000000" y="52"/>
</outline> </outline>
<outline id="outline13" corner-radius="1.000000"> <outline id="outline13" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/> <point x="0.000000" y="0.000000"/>
<point x="79.60975" y="0.000000"/> <point x="79.60975" y="0.000000"/>
<point x="79.60975" y="52.44877"/> <point x="79.60975" y="52"/>
<point x="0.000000" y="52.44877"/> <point x="0.000000" y="52"/>
</outline> </outline>
<outline id="spaceline" corner-radius="1.000000"> <outline id="spaceline" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/> <point x="0.000000" y="0.000000"/>
<point x="150.5853" y="0.000000"/> <point x="150.5853" y="0.000000"/>
<point x="150.5853" y="52.44877"/> <point x="150.5853" y="52"/>
<point x="0.000000" y="52.44877"/> <point x="0.000000" y="52"/>
</outline> </outline>
</geometry> </geometry>

View File

@ -0,0 +1,122 @@
<?xml version="1.0"?>
<geometry version="0.90">
<bounds x="0" y="10.000000" width="426.0000" height="296.5853"/>
<section angle="0">
<row orientation="1">
<key name="AD01" oref="outline2" />
<key name="AD02" oref="outline2" />
<key name="AD03" oref="outline2" />
<key name="AD04" oref="outline2" />
<key name="AD05" oref="outline2" />
<key name="AD06" oref="outline2" />
<key name="AD07" oref="outline2" />
<key name="AD08" oref="outline2" />
<key name="AD09" oref="outline2" />
<key name="AD10" oref="outline2" />
<key name="AD11" oref="outline2" />
</row>
</section>
<section angle="0">
<row orientation="1">
<key name="AC01" oref="outline2" />
<key name="AC02" oref="outline2" />
<key name="AC03" oref="outline2" />
<key name="AC04" oref="outline2" />
<key name="AC05" oref="outline2" />
<key name="AC06" oref="outline2" />
<key name="AC07" oref="outline2" />
<key name="AC08" oref="outline2" />
<key name="AC09" oref="outline2" />
<key name="AC10" oref="outline2" />
<key name="AC11" oref="outline2" />
</row>
</section>
<section angle="0">
<row orientation="1">
<key name="LFSH" oref="altline" />
<key name="AB01" oref="outline2" />
<key name="AB02" oref="outline2" />
<key name="AB03" oref="outline2" />
<key name="AB04" oref="outline2" />
<key name="AB05" oref="outline2" />
<key name="AB06" oref="outline2" />
<key name="AB07" oref="outline2" />
<key name="BKSP" oref="altline" />
</row>
</section>
<section angle="0">
<row orientation="1">
<key keycode="0" name="ABC123" oref="altline" />
<key name="I149" oref="altline" />
<key name="SPCE" oref="spaceline" />
<key name="AB08" oref="outline2" />
<key name="RTRN" oref="outline7" />
</row>
</section>
<outline id="outline2" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/>
<point x="32" y="0.000000"/>
<point x="32" y="52"/>
<point x="0.000000" y="52"/>
</outline>
<outline id="altline" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/>
<point x="48.39024" y="0.000000"/>
<point x="48.39024" y="52"/>
<point x="0.000000" y="52"/>
</outline>
<outline id="outline4" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/>
<point x="59.31707" y="0.000000"/>
<point x="59.31707" y="52"/>
<point x="0.000000" y="52"/>
</outline>
<outline id="outline5" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/>
<point x="59.31707" y="0.000000"/>
<point x="59.31707" y="52"/>
<point x="0.000000" y="52"/>
</outline>
<outline id="outline6" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/>
<point x="68.68292" y="0.000000"/>
<point x="68.68292" y="52"/>
<point x="0.000000" y="52"/>
</outline>
<outline id="outline7" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/>
<point x="88.97561" y="0.000000"/>
<point x="88.97561" y="52"/>
<point x="0.000000" y="52"/>
</outline>
<outline id="outline8" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/>
<point x="88.97561" y="0.000000"/>
<point x="88.97561" y="52"/>
<point x="0.000000" y="52"/>
</outline>
<outline id="outline9" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/>
<point x="109.2682" y="0.000000"/>
<point x="109.2682" y="52"/>
<point x="0.000000" y="52"/>
</outline>
<outline id="outline10" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/>
<point x="37.46341" y="0.000000"/>
<point x="37.46341" y="52"/>
<point x="0.000000" y="52"/>
</outline>
<outline id="outline13" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/>
<point x="79.60975" y="0.000000"/>
<point x="79.60975" y="52"/>
<point x="0.000000" y="52"/>
</outline>
<outline id="spaceline" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/>
<point x="150.5853" y="0.000000"/>
<point x="150.5853" y="52"/>
<point x="0.000000" y="52"/>
</outline>
</geometry>

View File

@ -0,0 +1,105 @@
<?xml version="1.0"?>
<geometry version="0.90">
<bounds x="0" y="10.000000" width="426.0000" height="296.5853"/>
<section angle="0">
<row orientation="1">
<key name="AD01" oref="outline2" />
<key name="AD02" oref="outline2" />
<key name="AD03" oref="outline2" />
<key name="AD04" oref="outline2" />
<key name="AD05" oref="outline2" />
</row>
</section>
<section angle="0">
<row orientation="1">
<key name="AC01" oref="outline2" />
<key name="AC02" oref="outline2" />
<key name="AC03" oref="outline2" />
<key name="AC04" oref="outline2" />
<key name="AC05" oref="outline2" />
</row>
</section>
<section angle="0">
<row orientation="1">
<key name="AB01" oref="outline2" />
<key name="AB02" oref="outline2" />
<key name="AB03" oref="outline2" />
<key name="AB04" oref="outline2" />
<key name="AB05" oref="outline2" />
</row>
</section>
<section angle="0">
<row orientation="1">
<key name="BKSP" oref="altline" />
<key name="AB06" oref="outline2" />
<key name="SPCE" oref="spaceline" />
<key name="RTRN" oref="outline7" />
</row>
</section>
<outline id="outline2" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/>
<point x="37.46341" y="0.000000"/>
<point x="37.46341" y="52.44877"/>
<point x="0.000000" y="52.44877"/>
</outline>
<outline id="altline" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/>
<point x="48.39024" y="0.000000"/>
<point x="48.39024" y="52.44877"/>
<point x="0.000000" y="52.44877"/>
</outline>
<outline id="outline4" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/>
<point x="59.31707" y="0.000000"/>
<point x="59.31707" y="52.44877"/>
<point x="0.000000" y="52.44877"/>
</outline>
<outline id="outline5" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/>
<point x="59.31707" y="0.000000"/>
<point x="59.31707" y="52.44877"/>
<point x="0.000000" y="52.44877"/>
</outline>
<outline id="outline6" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/>
<point x="68.68292" y="0.000000"/>
<point x="68.68292" y="52.44877"/>
<point x="0.000000" y="52.44877"/>
</outline>
<outline id="outline7" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/>
<point x="88.97561" y="0.000000"/>
<point x="88.97561" y="52.44877"/>
<point x="0.000000" y="52.44877"/>
</outline>
<outline id="outline8" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/>
<point x="88.97561" y="0.000000"/>
<point x="88.97561" y="52.44877"/>
<point x="0.000000" y="52.44877"/>
</outline>
<outline id="outline9" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/>
<point x="109.2682" y="0.000000"/>
<point x="109.2682" y="52.44877"/>
<point x="0.000000" y="52.44877"/>
</outline>
<outline id="outline10" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/>
<point x="37.46341" y="0.000000"/>
<point x="37.46341" y="52.44877"/>
<point x="0.000000" y="52.44877"/>
</outline>
<outline id="outline13" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/>
<point x="79.60975" y="0.000000"/>
<point x="79.60975" y="52.44877"/>
<point x="0.000000" y="52.44877"/>
</outline>
<outline id="spaceline" corner-radius="1.000000">
<point x="0.000000" y="0.000000"/>
<point x="120.5853" y="0.000000"/>
<point x="120.5853" y="52.44877"/>
<point x="0.000000" y="52.44877"/>
</outline>
</geometry>

View File

@ -24,6 +24,9 @@
<keyboard id="my" name="my" <keyboard id="my" name="my"
geometry="compact" symbols="my" geometry="compact" symbols="my"
longname="Myanmar" language="my"/> longname="Myanmar" language="my"/>
<keyboard id="nb" name="nb"
geometry="extended" symbols="nb"
longname="Norwegian" language="nb"/>
<keyboard id="ru" name="ru" <keyboard id="ru" name="ru"
geometry="compact" symbols="us" geometry="compact" symbols="us"
longname="Russian" language="ru"/> longname="Russian" language="ru"/>
@ -85,4 +88,13 @@
<keyboard id="te-inscript" name="te-inscript" <keyboard id="te-inscript" name="te-inscript"
geometry="compact" symbols="te-inscript" geometry="compact" symbols="te-inscript"
longname="Telugu (Inscript)" language="te"/> longname="Telugu (Inscript)" language="te"/>
<!-- Common keyboards -->
<keyboard id="number" name="number"
geometry="number-keypad" symbols="special/number"
longname="Numeric keypad" language="all"/>
<keyboard id="phone" name="phone"
geometry="number-keypad" symbols="special/number"
longname="Phone keypad" language="all"/>
</keyboards> </keyboards>

View File

@ -0,0 +1,206 @@
<?xml version='1.0' encoding='ASCII' standalone='yes'?>
<symbols version="0.90">
<key name="AD01">
<symbol label="q">q</symbol>
<symbol label="Q">Q</symbol>
<symbol label="1">1</symbol>
<symbol label="~">asciitilde</symbol>
</key>
<key name="AD02">
<symbol label="w">w</symbol>
<symbol label="W">W</symbol>
<symbol label="2">2</symbol>
<symbol label="`">quoteleft</symbol>
</key>
<key name="AD03">
<symbol label="e">e</symbol>
<symbol label="E">E</symbol>
<symbol label="3">3</symbol>
<symbol label="|">bar</symbol>
</key>
<key name="AD04">
<symbol label="r">r</symbol>
<symbol label="R">R</symbol>
<symbol label="4">4</symbol>
<symbol label="&#183;">U00B7</symbol>
</key>
<key name="AD05">
<symbol label="t">t</symbol>
<symbol label="T">T</symbol>
<symbol label="5">5</symbol>
<symbol label="&#8730;">squareroot</symbol>
</key>
<key name="AD06">
<symbol label="y">y</symbol>
<symbol label="Y">Y</symbol>
<symbol label="6">6</symbol>
<symbol label="&#960;">Greek_pi</symbol>
</key>
<key name="AD07">
<symbol label="u">u</symbol>
<symbol label="U">U</symbol>
<symbol label="7">7</symbol>
<symbol label="&#247;">division</symbol>
</key>
<key name="AD08">
<symbol label="i">i</symbol>
<symbol label="I">I</symbol>
<symbol label="8">8</symbol>
<symbol label="&#215;">multiply</symbol>
</key>
<key name="AD09">
<symbol label="o">o</symbol>
<symbol label="O">O</symbol>
<symbol label="9">9</symbol>
<symbol label="&#182;">paragraph</symbol>
</key>
<key name="AD10">
<symbol label="p">p</symbol>
<symbol label="P">P</symbol>
<symbol label="0">0</symbol>
<symbol label="&#9651;">U25B3</symbol>
</key>
<key name="AD11">
<symbol keyval="229" label="&#229;">aring</symbol>
<symbol keyval="197" label="&#197;">Aring</symbol>
<symbol label=""></symbol>
<symbol label=""></symbol>
<!-- Empty labels cause keys to be hidden when the level they are defined
for is shown. -->
</key>
<key name="AC01">
<symbol label="a">a</symbol>
<symbol label="A">A</symbol>
<symbol label="@">at</symbol>
<symbol label="&#169;">copyright</symbol>
</key>
<key name="AC02">
<symbol label="s">s</symbol>
<symbol label="S">S</symbol>
<symbol label="#">numbersign</symbol>
<symbol label="&#174;">U00AE</symbol>
</key>
<key name="AC03">
<symbol label="d">d</symbol>
<symbol label="D">D</symbol>
<symbol label="$">dollar</symbol>
<symbol label="&#163;">U00A3</symbol>
</key>
<key name="AC04">
<symbol label="f">f</symbol>
<symbol label="F">F</symbol>
<symbol label="%">percent</symbol>
<symbol label="&#8364;">EuroSign</symbol>
</key>
<key name="AC05">
<symbol label="g">g</symbol>
<symbol label="G">G</symbol>
<symbol label="&amp;">ampersand</symbol>
<symbol label="&#165;">U00A5</symbol>
</key>
<key name="AC06">
<symbol label="h">h</symbol>
<symbol label="H">H</symbol>
<symbol label="-">minus</symbol>
<symbol label="^">asciicircum</symbol>
</key>
<key name="AC07">
<symbol label="j">j</symbol>
<symbol label="J">J</symbol>
<symbol label="_">underscore</symbol>
<symbol label="&#176;">degree</symbol>
</key>
<key name="AC08">
<symbol label="k">k</symbol>
<symbol label="K">K</symbol>
<symbol label="+">plus</symbol>
<symbol label="=">equal</symbol>
</key>
<key name="AC09">
<symbol label="l">l</symbol>
<symbol label="L">L</symbol>
<symbol label="(">parenleft</symbol>
<symbol label="{">braceleft</symbol>
</key>
<key name="AC10">
<symbol keyval="248" label="&#248;">oslash</symbol>
<symbol keyval="216" label="&#216;">Oslash</symbol>
<symbol label=")">parenright</symbol>
<symbol label="}">braceright</symbol>
</key>
<key name="AC11">
<symbol keyval="230" label="&#230;">ae</symbol>
<symbol keyval="198" label="&#198;">AE</symbol>
<symbol label=""></symbol>
<symbol label=""></symbol>
</key>
<key name="RTRN">
<symbol keyval="65293" icon="key-enter">Return</symbol>
</key>
<key name="LFSH">
<keysym keyval="65505" icon="key-shift">Shift_L</keysym>
<keysym keyval="65505" icon="key-shift">Shift_L</keysym>
<keysym keyval="65505" label="=/+">Shift_L</keysym>
<keysym keyval="65505" label="123">Shift_L</keysym>
</key>
<key name="AB01">
<symbol label="z">z</symbol>
<symbol label="Z">Z</symbol>
<symbol label=",">comma</symbol>
<symbol label="\">backslash</symbol>
</key>
<key name="AB02">
<symbol label="x">x</symbol>
<symbol label="X">X</symbol>
<symbol label="&quot;">quotedbl</symbol>
<symbol label="/">slash</symbol>
</key>
<key name="AB03">
<symbol label="c">c</symbol>
<symbol label="C">C</symbol>
<symbol label="'">quoteright</symbol>
<symbol label="&lt;">less</symbol>
</key>
<key name="AB04">
<symbol label="v">v</symbol>
<symbol label="V">V</symbol>
<symbol label=":">colon</symbol>
<symbol label="&gt;">greater</symbol>
</key>
<key name="AB05">
<symbol label="b">b</symbol>
<symbol label="B">B</symbol>
<symbol label=";">semicolon</symbol>
<symbol label="=">equal</symbol>
</key>
<key name="AB06">
<symbol label="n">n</symbol>
<symbol label="N">N</symbol>
<symbol label="!">exclam</symbol>
<symbol label="[">bracketleft</symbol>
</key>
<key name="AB07">
<symbol label="m">m</symbol>
<symbol label="M">M</symbol>
<symbol label="?">question</symbol>
<symbol label="]">bracketright</symbol>
</key>
<key name="AB08">
<symbol label=".">period</symbol>
</key>
<key name="ABC123">
<symbol label="123">show-numbers</symbol>
<symbol label="123">show-numbers</symbol>
<symbol label="ABC">show-letters</symbol>
<symbol label="ABC">show-letters</symbol>
</key>
<key name="I149">
<symbol icon="keyboard-mode-symbolic" tooltip="Setup">preferences</symbol>
</key>
<key name="SPCE">
<symbol label=" ">space</symbol>
</key>
<key name="BKSP">
<symbol keyval="65288" icon="edit-clear-symbolic">BackSpace</symbol>
</key>
</symbols>

View File

@ -0,0 +1,60 @@
<?xml version='1.0' encoding='ASCII' standalone='yes'?>
<symbols version="0.90">
<key name="AD01">
<symbol label="1">1</symbol>
</key>
<key name="AD02">
<symbol label="2">2</symbol>
</key>
<key name="AD03">
<symbol label="3">3</symbol>
</key>
<key name="AD04">
<symbol label="(">parenleft</symbol>
</key>
<key name="AD05">
<symbol label=")">parenright</symbol>
</key>
<key name="AC01">
<symbol label="4">4</symbol>
</key>
<key name="AC02">
<symbol label="5">5</symbol>
</key>
<key name="AC03">
<symbol label="6">6</symbol>
</key>
<key name="AC04">
<symbol label="#">numbersign</symbol>
</key>
<key name="AC05">
<symbol label="*">asterisk</symbol>
</key>
<key name="AB01">
<symbol label="7">7</symbol>
</key>
<key name="AB02">
<symbol label="8">8</symbol>
</key>
<key name="AB03">
<symbol label="9">9</symbol>
</key>
<key name="AB04">
<symbol label="+">plus</symbol>
</key>
<key name="AB05">
<symbol label="-">minus</symbol>
</key>
<key name="AB06">
<symbol label="0">0</symbol>
</key>
<key name="RTRN">
<symbol keyval="65293" icon="key-enter">Return</symbol>
</key>
<key name="SPCE">
<symbol label=" ">space</symbol>
</key>
<key name="BKSP">
<symbol keyval="65288" icon="edit-clear-symbolic">BackSpace</symbol>
</key>
</symbols>

View File

@ -1,304 +1,194 @@
<?xml version="1.0"?> <?xml version='1.0' encoding='ASCII' standalone='yes'?>
<symbols version="0.90"> <symbols version="0.90">
<key keycode="9" name="ESC"> <key name="AD01">
<keysym keyval="65307">Escape</keysym> <symbol label="q">q</symbol>
</key> <symbol label="Q">Q</symbol>
<key keycode="67" name="FK01"> <symbol label="1">1</symbol>
<keysym keyval="65470">F1</keysym> <symbol label="~">asciitilde</symbol>
</key> </key>
<key keycode="68" name="FK02"> <key name="AD02">
<keysym keyval="65471">F2</keysym> <symbol label="w">w</symbol>
</key> <symbol label="W">W</symbol>
<key keycode="69" name="FK03"> <symbol label="2">2</symbol>
<keysym keyval="65472">F3</keysym> <symbol label="`">quoteleft</symbol>
</key> </key>
<key keycode="70" name="FK04"> <key name="AD03">
<keysym keyval="65473">F4</keysym> <symbol label="e">e</symbol>
</key> <symbol label="E">E</symbol>
<key keycode="71" name="FK05"> <symbol label="3">3</symbol>
<keysym keyval="65474">F5</keysym> <symbol label="|">bar</symbol>
</key> </key>
<key keycode="72" name="FK06"> <key name="AD04">
<keysym keyval="65475">F6</keysym> <symbol label="r">r</symbol>
</key> <symbol label="R">R</symbol>
<key keycode="73" name="FK07"> <symbol label="4">4</symbol>
<keysym keyval="65476">F7</keysym> <symbol label="&#183;">U00B7</symbol>
</key> </key>
<key keycode="74" name="FK08"> <key name="AD05">
<keysym keyval="65477">F8</keysym> <symbol label="t">t</symbol>
</key> <symbol label="T">T</symbol>
<key keycode="75" name="FK09"> <symbol label="5">5</symbol>
<keysym keyval="65478">F9</keysym> <symbol label="&#8730;">squareroot</symbol>
</key> </key>
<key keycode="76" name="FK10"> <key name="AD06">
<keysym keyval="65479">F10</keysym> <symbol label="y">y</symbol>
</key> <symbol label="Y">Y</symbol>
<key keycode="95" name="FK11"> <symbol label="6">6</symbol>
<keysym keyval="65480">F11</keysym> <symbol label="&#960;">Greek_pi</symbol>
</key> </key>
<key keycode="96" name="FK12"> <key name="AD07">
<keysym keyval="65481">F12</keysym> <symbol label="u">u</symbol>
</key> <symbol label="U">U</symbol>
<key keycode="49" name="TLDE"> <symbol label="7">7</symbol>
<keysym keyval="96">quoteleft</keysym> <symbol label="&#247;">division</symbol>
<keysym keyval="126">asciitilde</keysym> </key>
</key> <key name="AD08">
<key keycode="10" name="AE01"> <symbol label="i">i</symbol>
<keysym keyval="49">1</keysym> <symbol label="I">I</symbol>
<keysym keyval="33">exclam</keysym> <symbol label="8">8</symbol>
</key> <symbol label="&#215;">multiply</symbol>
<key keycode="11" name="AE02"> </key>
<keysym keyval="50">2</keysym> <key name="AD09">
<keysym keyval="64">at</keysym> <symbol label="o">o</symbol>
</key> <symbol label="O">O</symbol>
<key keycode="12" name="AE03"> <symbol label="9">9</symbol>
<keysym keyval="51">3</keysym> <symbol label="&#182;">paragraph</symbol>
<keysym keyval="35">numbersign</keysym> </key>
</key> <key name="AD10">
<key keycode="13" name="AE04"> <symbol label="p">p</symbol>
<keysym keyval="52">4</keysym> <symbol label="P">P</symbol>
<keysym keyval="36">dollar</keysym> <symbol label="0">0</symbol>
</key> <symbol label="&#9651;">U25B3</symbol>
<key keycode="14" name="AE05"> </key>
<keysym keyval="53">5</keysym> <key name="AC01">
<keysym keyval="37">percent</keysym> <symbol label="a">a</symbol>
<keysym keyval="8364">EuroSign</keysym> <symbol label="A">A</symbol>
</key> <symbol label="@">at</symbol>
<key keycode="15" name="AE06"> <symbol label="&#169;">copyright</symbol>
<keysym keyval="54">6</keysym> </key>
<keysym keyval="94">asciicircum</keysym> <key name="AC02">
</key> <symbol label="s">s</symbol>
<key keycode="16" name="AE07"> <symbol label="S">S</symbol>
<keysym keyval="55">7</keysym> <symbol label="#">numbersign</symbol>
<keysym keyval="38">ampersand</keysym> <symbol label="&#174;">U00AE</symbol>
</key> </key>
<key keycode="17" name="AE08"> <key name="AC03">
<keysym keyval="56">8</keysym> <symbol label="d">d</symbol>
<keysym keyval="42">asterisk</keysym> <symbol label="D">D</symbol>
</key> <symbol label="$">dollar</symbol>
<key keycode="18" name="AE09"> <symbol label="&#163;">U00A3</symbol>
<keysym keyval="57">9</keysym> </key>
<keysym keyval="40">parenleft</keysym> <key name="AC04">
</key> <symbol label="f">f</symbol>
<key keycode="19" name="AE10"> <symbol label="F">F</symbol>
<keysym keyval="48">0</keysym> <symbol label="%">percent</symbol>
<keysym keyval="41">parenright</keysym> <symbol label="&#8364;">EuroSign</symbol>
</key> </key>
<key keycode="20" name="AE11"> <key name="AC05">
<keysym keyval="45">minus</keysym> <symbol label="g">g</symbol>
<keysym keyval="95">underscore</keysym> <symbol label="G">G</symbol>
</key> <symbol label="&amp;">ampersand</symbol>
<key keycode="21" name="AE12"> <symbol label="&#165;">U00A5</symbol>
<keysym keyval="61">equal</keysym> </key>
<keysym keyval="43">plus</keysym> <key name="AC06">
</key> <symbol label="h">h</symbol>
<key keycode="22" name="BKSP"> <symbol label="H">H</symbol>
<keysym keyval="65288">BackSpace</keysym> <symbol label="-">minus</symbol>
</key> <symbol label="^">asciicircum</symbol>
<key keycode="23" name="TAB"> </key>
<keysym keyval="65289">Tab</keysym> <key name="AC07">
<keysym keyval="65056">ISO_Left_Tab</keysym> <symbol label="j">j</symbol>
</key> <symbol label="J">J</symbol>
<key keycode="24" name="AD01"> <symbol label="_">underscore</symbol>
<keysym keyval="113">q</keysym> <symbol label="&#176;">degree</symbol>
<keysym keyval="81">Q</keysym> </key>
<keysym keyval="49">1</keysym> <key name="AC08">
</key> <symbol label="k">k</symbol>
<key keycode="25" name="AD02"> <symbol label="K">K</symbol>
<keysym keyval="119">w</keysym> <symbol label="+">plus</symbol>
<keysym keyval="87">W</keysym> <symbol label="=">equal</symbol>
<keysym keyval="50">2</keysym> </key>
</key> <key name="AC09">
<key keycode="26" name="AD03"> <symbol label="l">l</symbol>
<keysym keyval="101">e</keysym> <symbol label="L">L</symbol>
<keysym keyval="69">E</keysym> <symbol label="(">parenleft</symbol>
<keysym keyval="51">3</keysym> <symbol label="{">braceleft</symbol>
</key> </key>
<key keycode="27" name="AD04"> <key name="AC10">
<keysym keyval="114">r</keysym> <!-- Empty labels cause keys to be hidden when the level they are defined
<keysym keyval="82">R</keysym> for is shown. -->
<keysym keyval="52">4</keysym> <symbol label=""></symbol>
</key> <symbol label=""></symbol>
<key keycode="28" name="AD05"> <symbol label=")">parenright</symbol>
<keysym keyval="116">t</keysym> <symbol label="}">braceright</symbol>
<keysym keyval="84">T</keysym> </key>
<keysym keyval="53">5</keysym> <key name="RTRN">
</key> <symbol keyval="65293" icon="key-enter">Return</symbol>
<key keycode="29" name="AD06"> </key>
<keysym keyval="121">y</keysym> <key name="LFSH">
<keysym keyval="89">Y</keysym> <keysym keyval="65505" icon="key-shift">Shift_L</keysym>
<keysym keyval="54">6</keysym> <keysym keyval="65505" icon="key-shift">Shift_L</keysym>
</key> <keysym keyval="65505" label="=/+">Shift_L</keysym>
<key keycode="30" name="AD07"> <keysym keyval="65505" label="123">Shift_L</keysym>
<keysym keyval="117">u</keysym> </key>
<keysym keyval="85">U</keysym> <key name="AB01">
<keysym keyval="55">7</keysym> <symbol label="z">z</symbol>
</key> <symbol label="Z">Z</symbol>
<key keycode="31" name="AD08"> <symbol label=",">comma</symbol>
<keysym keyval="105">i</keysym> <symbol label="\">backslash</symbol>
<keysym keyval="73">I</keysym> </key>
<keysym keyval="56">8</keysym> <key name="AB02">
</key> <symbol label="x">x</symbol>
<key keycode="32" name="AD09"> <symbol label="X">X</symbol>
<keysym keyval="111">o</keysym> <symbol label="&quot;">quotedbl</symbol>
<keysym keyval="79">O</keysym> <symbol label="/">slash</symbol>
<keysym keyval="57">9</keysym> </key>
</key> <key name="AB03">
<key keycode="33" name="AD10"> <symbol label="c">c</symbol>
<keysym keyval="112">p</keysym> <symbol label="C">C</symbol>
<keysym keyval="80">P</keysym> <symbol label="'">quoteright</symbol>
<keysym keyval="48">0</keysym> <symbol label="&lt;">less</symbol>
</key> </key>
<key keycode="34" name="AD11"> <key name="AB04">
<keysym keyval="91">bracketleft</keysym> <symbol label="v">v</symbol>
<keysym keyval="123">braceleft</keysym> <symbol label="V">V</symbol>
</key> <symbol label=":">colon</symbol>
<key keycode="35" name="AD12"> <symbol label="&gt;">greater</symbol>
<keysym keyval="93">bracketright</keysym> </key>
<keysym keyval="125">braceright</keysym> <key name="AB05">
</key> <symbol label="b">b</symbol>
<key keycode="51" name="BKSL"> <symbol label="B">B</symbol>
<keysym keyval="92">backslash</keysym> <symbol label=";">semicolon</symbol>
<keysym keyval="124">bar</keysym> <symbol label="=">equal</symbol>
</key> </key>
<key keycode="66" name="ALTGR"> <key name="AB06">
<keysym keyval="65027">ISO_Level3_Shift</keysym> <symbol label="n">n</symbol>
</key> <symbol label="N">N</symbol>
<key keycode="38" name="AC01"> <symbol label="!">exclam</symbol>
<keysym keyval="97">a</keysym> <symbol label="[">bracketleft</symbol>
<keysym keyval="65">A</keysym> </key>
<keysym keyval="64">at</keysym> <key name="AB07">
</key> <symbol label="m">m</symbol>
<key keycode="39" name="AC02"> <symbol label="M">M</symbol>
<keysym keyval="115">s</keysym> <symbol label="?">question</symbol>
<keysym keyval="83">S</keysym> <symbol label="]">bracketright</symbol>
<keysym keyval="35">numbersign</keysym> </key>
</key> <key name="AB08">
<key keycode="40" name="AC03"> <symbol label=".">period</symbol>
<keysym keyval="100">d</keysym> </key>
<keysym keyval="68">D</keysym> <key name="ABC123">
<keysym keyval="36">dollar</keysym> <symbol label="123">show-numbers</symbol>
</key> <symbol label="123">show-numbers</symbol>
<key keycode="41" name="AC04"> <symbol label="ABC">show-letters</symbol>
<keysym keyval="102">f</keysym> <symbol label="ABC">show-letters</symbol>
<keysym keyval="70">F</keysym> </key>
<keysym keyval="37">percent</keysym> <key name="I149">
</key> <symbol label="&#9786;" icon="keyboard-mode-symbolic" tooltip="Setup">preferences</symbol>
<key keycode="42" name="AC05"> </key>
<keysym keyval="103">g</keysym> <key name="SPCE">
<keysym keyval="71">G</keysym> <symbol label=" ">space</symbol>
<keysym keyval="38">ampersand</keysym> </key>
</key> <key name="BKSP">
<key keycode="43" name="AC06"> <symbol keyval="65288" icon="edit-clear-symbolic">BackSpace</symbol>
<keysym keyval="104">h</keysym>
<keysym keyval="72">H</keysym>
<keysym keyval="45">minus</keysym>
</key>
<key keycode="44" name="AC07">
<keysym keyval="106">j</keysym>
<keysym keyval="74">J</keysym>
<keysym keyval="95">underscore</keysym>
</key>
<key keycode="45" name="AC08">
<keysym keyval="107">k</keysym>
<keysym keyval="75">K</keysym>
<keysym keyval="123">braceleft</keysym>
</key>
<key keycode="46" name="AC09">
<keysym keyval="108">l</keysym>
<keysym keyval="76">L</keysym>
<keysym keyval="125">braceright</keysym>
</key>
<key keycode="47" name="AC10">
<keysym keyval="59">semicolon</keysym>
<keysym keyval="58">colon</keysym>
</key>
<key keycode="48" name="AC11">
<keysym keyval="39">quoteright</keysym>
<keysym keyval="34">quotedbl</keysym>
</key>
<key keycode="36" name="RTRN">
<keysym keyval="65293">Return</keysym>
</key>
<key keycode="50" name="LFSH">
<keysym keyval="65505">Shift_L</keysym>
</key>
<key keycode="52" name="AB01">
<keysym keyval="122">z</keysym>
<keysym keyval="90">Z</keysym>
<keysym keyval="43">plus</keysym>
</key>
<key keycode="53" name="AB02">
<keysym keyval="120">x</keysym>
<keysym keyval="88">X</keysym>
<keysym keyval="34">quotedbl</keysym>
</key>
<key keycode="54" name="AB03">
<keysym keyval="99">c</keysym>
<keysym keyval="67">C</keysym>
<keysym keyval="39">quoteright</keysym>
</key>
<key keycode="55" name="AB04">
<keysym keyval="118">v</keysym>
<keysym keyval="86">V</keysym>
<keysym keyval="58">colon</keysym>
</key>
<key keycode="56" name="AB05">
<keysym keyval="98">b</keysym>
<keysym keyval="66">B</keysym>
<keysym keyval="59">semicolon</keysym>
</key>
<key keycode="57" name="AB06">
<keysym keyval="110">n</keysym>
<keysym keyval="78">N</keysym>
<keysym keyval="33">exclam</keysym>
</key>
<key keycode="58" name="AB07">
<keysym keyval="109">m</keysym>
<keysym keyval="77">M</keysym>
<keysym keyval="63">question</keysym>
</key>
<key keycode="59" name="AB08">
<keysym keyval="44">comma</keysym>
<keysym keyval="60">less</keysym>
</key>
<key keycode="60" name="AB09">
<keysym keyval="46">period</keysym>
<keysym keyval="62">greater</keysym>
</key>
<key keycode="61" name="AB10">
<keysym keyval="47">slash</keysym>
<keysym keyval="63">question</keysym>
</key>
<key keycode="62" name="RTSH">
<keysym keyval="65506">Shift_R</keysym>
</key>
<key keycode="149" name="I149">
<symbol label="⌨" icon="input-keyboard-symbolic" tooltip="Change keyboard">cycle-keyboard</symbol>
</key>
<key keycode="150" name="I150">
<symbol label="☺" icon="preferences-system-symbolic" tooltip="Setup">preferences</symbol>
</key>
<key keycode="37" name="LCTL">
<keysym keyval="65507">Control_L</keysym>
</key>
<key keycode="64" name="LALT">
<keysym keyval="65513">Alt_L</keysym>
<keysym keyval="65511">Meta_L</keysym>
</key>
<key keycode="65" name="SPCE">
<keysym keyval="32">space</keysym>
</key>
<key keycode="113" name="LEFT">
<keysym keyval="65361">Left</keysym>
</key>
<key keycode="111" name="UP">
<keysym keyval="65362">Up</keysym>
</key>
<key keycode="116" name="DOWN">
<keysym keyval="65364">Down</keysym>
</key>
<key keycode="114" name="RGHT">
<keysym keyval="65363">Right</keysym>
</key> </key>
</symbols> </symbols>

View File

@ -1,57 +1,12 @@
gnome = import('gnome')
install_data( squeekboard_resources = gnome.compile_resources(
'themes/default.css', 'squeekboard-resources',
install_dir: pkgdatadir + '/themes', 'squeekboard.gresources.xml',
c_name: 'squeekboard',
) )
install_data(
'keyboards/keyboards.xml',
install_dir: pkgdatadir + '/keyboards/',
)
install_data(
'keyboards/geometry/compact.xml',
install_dir: pkgdatadir + '/keyboards/geometry/',
)
symbols = [
'ar.xml',
'as-inscript.xml',
'be.xml',
'bn-inscript.xml',
'fa.xml',
'gu-inscript.xml',
'he.xml',
'hi-inscript.xml',
'ja-kana.xml',
'kk.xml',
'kn-inscript.xml',
'ks-inscript.xml',
'ks.xml',
'mai-inscript.xml',
'ml-inscript.xml',
'mr-inscript.xml',
'my.xml',
'or-inscript.xml',
'pa-inscript.xml',
'ru.xml',
'sd-inscript.xml',
'ta-inscript.xml',
'te-inscript.xml',
'th.xml',
'ua.xml',
'ug.xml',
'us.xml',
'zh-bopomofo.xml',
]
foreach symbol: symbols
install_data(
'keyboards/symbols/' + symbol,
install_dir: pkgdatadir + '/keyboards/symbols/',
)
endforeach
desktop_file = 'sm.puri.Squeekboard.desktop' desktop_file = 'sm.puri.Squeekboard.desktop'
i18n.merge_file('desktop', i18n.merge_file('desktop',

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/sm/puri/squeekboard">
<file compressed="true">style.css</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/geometry/compact.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/geometry/extended.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/geometry/number-keypad.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/keyboards.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/ar.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/as-inscript.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/be.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/bn-inscript.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/fa.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/gu-inscript.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/he.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/hi-inscript.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/ja-kana.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/kk.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/kn-inscript.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/ks-inscript.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/ks.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/mai-inscript.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/ml-inscript.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/mr-inscript.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/my.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/nb.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/or-inscript.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/pa-inscript.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/ru.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/sd-inscript.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/ta-inscript.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/te-inscript.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/th.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/ua.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/ug.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/us.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/zh-bopomofo.xml</file>
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/special/number.xml</file>
<file>icons/key-enter.svg</file>
<file>icons/key-shift.svg</file>
<file>icons/keyboard-mode-symbolic.svg</file>
</gresource>
</gresources>

6
debian/control vendored
View File

@ -11,8 +11,10 @@ Build-Depends:
libcroco3-dev, libcroco3-dev,
libwayland-dev (>= 1.16), libwayland-dev (>= 1.16),
rustc, rustc,
virtboard, wayland-protocols (>= 1.14),
wayland-protocols (>= 1.14) # for running the tests
xvfb,
xauth,
Standards-Version: 4.1.3 Standards-Version: 4.1.3
Homepage: https://source.puri.sm/Librem5/squeekboard Homepage: https://source.puri.sm/Librem5/squeekboard

53
debian/copyright vendored
View File

@ -3,7 +3,58 @@ Upstream-Name: evscript
Source: https://source.puri.sm/david.boddie/evscript Source: https://source.puri.sm/david.boddie/evscript
Files: * Files: *
Copyright: 2019 Purism SPC Copyright: 2010-2011 Daiki Ueno <ueno@unixuser.org>
2010-2011 Red Hat, Inc.
2019 Purism SPC
License: GPL-3+
Files: eek/layersurface.c
src/wayland.c
src/key-emitter.c
meson.build
src/meson.build
po/meson.build
Copyright: 2018-2019 Purism SPC
License: GPL-3+
Files: eekboard/keymap.c
Copyright: 2000 Red Hat, Inc.
2019 Purism, SPC
License: LGPL-2+
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
Files: protocols/wlr-layer-shell-unstable-v1.xml
Copytight: Copyright © 2017 Drew DeVault
License: X11
Permission to use, copy, modify, distribute, and sell this software and
its documentation for any purpose is hereby granted without fee, provided
that the above copyright notice appear in all copies and fthat both that
copyright notice and this permission notice appear in supporting
documentation, and that the name of the copyright holders not be used in
advertising or publicity pertaining to distribution of the software
without specific, written prior permission. The copyright holders make
no representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied warranty.
.
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
License: GPL-3+ License: GPL-3+
This package is free software; you can redistribute it and/or modify This package is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by

View File

View File

@ -26,9 +26,7 @@
* shall be used to implement #EekKeyboard and #EekSection. * shall be used to implement #EekKeyboard and #EekSection.
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */
#include "eek-container.h" #include "eek-container.h"
@ -40,23 +38,19 @@ enum {
static guint signals[LAST_SIGNAL] = { 0, }; static guint signals[LAST_SIGNAL] = { 0, };
G_DEFINE_ABSTRACT_TYPE (EekContainer, eek_container, EEK_TYPE_ELEMENT); typedef struct _EekContainerPrivate
#define EEK_CONTAINER_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_CONTAINER, EekContainerPrivate))
struct _EekContainerPrivate
{ {
GList *head; GList *head;
GList *last; GList *last;
}; } EekContainerPrivate;
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (EekContainer, eek_container, EEK_TYPE_ELEMENT)
static void static void
eek_container_real_add_child (EekContainer *self, eek_container_real_add_child (EekContainer *self,
EekElement *child) EekElement *child)
{ {
EekContainerPrivate *priv = EEK_CONTAINER_GET_PRIVATE(self); EekContainerPrivate *priv = eek_container_get_instance_private (self);
g_return_if_fail (EEK_IS_ELEMENT(child)); g_return_if_fail (EEK_IS_ELEMENT(child));
g_object_ref (child); g_object_ref (child);
@ -75,7 +69,7 @@ static void
eek_container_real_remove_child (EekContainer *self, eek_container_real_remove_child (EekContainer *self,
EekElement *child) EekElement *child)
{ {
EekContainerPrivate *priv = EEK_CONTAINER_GET_PRIVATE(self); EekContainerPrivate *priv = eek_container_get_instance_private (self);
GList *head; GList *head;
g_return_if_fail (EEK_IS_ELEMENT(child)); g_return_if_fail (EEK_IS_ELEMENT(child));
@ -94,7 +88,7 @@ eek_container_real_foreach_child (EekContainer *self,
EekCallback callback, EekCallback callback,
gpointer user_data) gpointer user_data)
{ {
EekContainerPrivate *priv = EEK_CONTAINER_GET_PRIVATE(self); EekContainerPrivate *priv = eek_container_get_instance_private (self);
GList *head; GList *head;
for (head = priv->head; head; head = g_list_next (head)) for (head = priv->head; head; head = g_list_next (head))
@ -106,7 +100,7 @@ eek_container_real_find (EekContainer *self,
EekCompareFunc func, EekCompareFunc func,
gpointer user_data) gpointer user_data)
{ {
EekContainerPrivate *priv = EEK_CONTAINER_GET_PRIVATE(self); EekContainerPrivate *priv = eek_container_get_instance_private (self);
GList *head; GList *head;
head = g_list_find_custom (priv->head, user_data, (GCompareFunc)func); head = g_list_find_custom (priv->head, user_data, (GCompareFunc)func);
@ -118,7 +112,8 @@ eek_container_real_find (EekContainer *self,
static void static void
eek_container_dispose (GObject *object) eek_container_dispose (GObject *object)
{ {
EekContainerPrivate *priv = EEK_CONTAINER_GET_PRIVATE(object); EekContainer *self = EEK_CONTAINER (object);
EekContainerPrivate *priv = eek_container_get_instance_private (self);
GList *head; GList *head;
for (head = priv->head; head; head = priv->head) { for (head = priv->head; head; head = priv->head) {
@ -134,9 +129,6 @@ eek_container_class_init (EekContainerClass *klass)
{ {
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (gobject_class,
sizeof (EekContainerPrivate));
klass->add_child = eek_container_real_add_child; klass->add_child = eek_container_real_add_child;
klass->remove_child = eek_container_real_remove_child; klass->remove_child = eek_container_real_remove_child;
klass->foreach_child = eek_container_real_foreach_child; klass->foreach_child = eek_container_real_foreach_child;
@ -189,7 +181,7 @@ eek_container_class_init (EekContainerClass *klass)
static void static void
eek_container_init (EekContainer *self) eek_container_init (EekContainer *self)
{ {
self->priv = EEK_CONTAINER_GET_PRIVATE(self); /* void */
} }
/** /**

View File

@ -30,14 +30,7 @@
G_BEGIN_DECLS G_BEGIN_DECLS
#define EEK_TYPE_CONTAINER (eek_container_get_type()) #define EEK_TYPE_CONTAINER (eek_container_get_type())
#define EEK_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEK_TYPE_CONTAINER, EekContainer)) G_DECLARE_DERIVABLE_TYPE (EekContainer, eek_container, EEK, CONTAINER, EekElement)
#define EEK_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEK_TYPE_CONTAINER, EekContainerClass))
#define EEK_IS_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEK_TYPE_CONTAINER))
#define EEK_IS_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_CONTAINER))
#define EEK_CONTAINER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_CONTAINER, EekContainerClass))
typedef struct _EekContainerClass EekContainerClass;
typedef struct _EekContainerPrivate EekContainerPrivate;
/** /**
* EekCallback: * EekCallback:
@ -50,14 +43,6 @@ typedef struct _EekContainerPrivate EekContainerPrivate;
typedef void (*EekCallback) (EekElement *element, gpointer user_data); typedef void (*EekCallback) (EekElement *element, gpointer user_data);
typedef gint (*EekCompareFunc) (EekElement *element, gpointer user_data); typedef gint (*EekCompareFunc) (EekElement *element, gpointer user_data);
struct _EekContainer
{
/*< private >*/
EekElement parent;
EekContainerPrivate *priv;
};
/** /**
* EekContainerClass: * EekContainerClass:
* @foreach_child: virtual function for iterating over the container's children * @foreach_child: virtual function for iterating over the container's children

View File

@ -26,9 +26,7 @@
* shall be used to implement #EekKeyboard, #EekSection, or #EekKey. * shall be used to implement #EekKeyboard, #EekSection, or #EekKey.
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */
#include <string.h> #include <string.h>
@ -52,20 +50,16 @@ enum {
static guint signals[LAST_SIGNAL] = { 0, }; static guint signals[LAST_SIGNAL] = { 0, };
G_DEFINE_ABSTRACT_TYPE (EekElement, eek_element, G_TYPE_OBJECT); typedef struct _EekElementPrivate
#define EEK_ELEMENT_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_ELEMENT, EekElementPrivate))
struct _EekElementPrivate
{ {
gchar *name; gchar *name;
EekBounds bounds; EekBounds bounds;
EekElement *parent; EekElement *parent;
gint group; gint group;
gint level; gint level;
}; } EekElementPrivate;
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (EekElement, eek_element, G_TYPE_OBJECT)
static void static void
eek_element_real_symbol_index_changed (EekElement *self, eek_element_real_symbol_index_changed (EekElement *self,
@ -78,7 +72,8 @@ eek_element_real_symbol_index_changed (EekElement *self,
static void static void
eek_element_finalize (GObject *object) eek_element_finalize (GObject *object)
{ {
EekElementPrivate *priv = EEK_ELEMENT_GET_PRIVATE(object); EekElement *self = EEK_ELEMENT (object);
EekElementPrivate *priv = eek_element_get_instance_private (self);
g_free (priv->name); g_free (priv->name);
G_OBJECT_CLASS (eek_element_parent_class)->finalize (object); G_OBJECT_CLASS (eek_element_parent_class)->finalize (object);
@ -105,6 +100,7 @@ eek_element_set_property (GObject *object,
break; break;
case PROP_LEVEL: case PROP_LEVEL:
eek_element_set_level (element, g_value_get_int (value)); eek_element_set_level (element, g_value_get_int (value));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -146,9 +142,6 @@ eek_element_class_init (EekElementClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec; GParamSpec *pspec;
g_type_class_add_private (gobject_class,
sizeof (EekElementPrivate));
/* signals */ /* signals */
klass->symbol_index_changed = eek_element_real_symbol_index_changed; klass->symbol_index_changed = eek_element_real_symbol_index_changed;
@ -238,9 +231,8 @@ eek_element_class_init (EekElementClass *klass)
static void static void
eek_element_init (EekElement *self) eek_element_init (EekElement *self)
{ {
EekElementPrivate *priv; EekElementPrivate *priv = eek_element_get_instance_private (self);
priv = self->priv = EEK_ELEMENT_GET_PRIVATE(self);
priv->group = -1; priv->group = -1;
priv->level = -1; priv->level = -1;
} }
@ -259,10 +251,12 @@ eek_element_set_parent (EekElement *element,
g_return_if_fail (EEK_IS_ELEMENT(element)); g_return_if_fail (EEK_IS_ELEMENT(element));
g_return_if_fail (parent == NULL || EEK_IS_ELEMENT(parent)); g_return_if_fail (parent == NULL || EEK_IS_ELEMENT(parent));
if (element->priv->parent == parent) EekElementPrivate *priv = eek_element_get_instance_private (element);
if (priv->parent == parent)
return; return;
if (element->priv->parent != NULL) { if (priv->parent != NULL) {
/* release self-reference acquired when setting parent */ /* release self-reference acquired when setting parent */
g_object_unref (element); g_object_unref (element);
} }
@ -271,7 +265,7 @@ eek_element_set_parent (EekElement *element,
g_object_ref (element); g_object_ref (element);
} }
element->priv->parent = parent; priv->parent = parent;
} }
/** /**
@ -285,7 +279,10 @@ EekElement *
eek_element_get_parent (EekElement *element) eek_element_get_parent (EekElement *element)
{ {
g_return_val_if_fail (EEK_IS_ELEMENT(element), NULL); g_return_val_if_fail (EEK_IS_ELEMENT(element), NULL);
return element->priv->parent;
EekElementPrivate *priv = eek_element_get_instance_private (element);
return priv->parent;
} }
/** /**
@ -300,8 +297,11 @@ eek_element_set_name (EekElement *element,
const gchar *name) const gchar *name)
{ {
g_return_if_fail (EEK_IS_ELEMENT(element)); g_return_if_fail (EEK_IS_ELEMENT(element));
g_free (element->priv->name);
element->priv->name = g_strdup (name); EekElementPrivate *priv = eek_element_get_instance_private (element);
g_free (priv->name);
priv->name = g_strdup (name);
} }
/** /**
@ -315,7 +315,10 @@ const gchar *
eek_element_get_name (EekElement *element) eek_element_get_name (EekElement *element)
{ {
g_return_val_if_fail (EEK_IS_ELEMENT(element), NULL); g_return_val_if_fail (EEK_IS_ELEMENT(element), NULL);
return element->priv->name;
EekElementPrivate *priv = eek_element_get_instance_private (element);
return priv->name;
} }
/** /**
@ -332,7 +335,10 @@ eek_element_set_bounds (EekElement *element,
EekBounds *bounds) EekBounds *bounds)
{ {
g_return_if_fail (EEK_IS_ELEMENT(element)); g_return_if_fail (EEK_IS_ELEMENT(element));
memcpy (&element->priv->bounds, bounds, sizeof(EekBounds));
EekElementPrivate *priv = eek_element_get_instance_private (element);
memcpy (&priv->bounds, bounds, sizeof(EekBounds));
} }
/** /**
@ -350,7 +356,10 @@ eek_element_get_bounds (EekElement *element,
{ {
g_return_if_fail (EEK_IS_ELEMENT(element)); g_return_if_fail (EEK_IS_ELEMENT(element));
g_return_if_fail (bounds != NULL); g_return_if_fail (bounds != NULL);
memcpy (bounds, &element->priv->bounds, sizeof(EekBounds));
EekElementPrivate *priv = eek_element_get_instance_private (element);
memcpy (bounds, &priv->bounds, sizeof(EekBounds));
} }
/** /**
@ -486,11 +495,14 @@ eek_element_set_group (EekElement *element,
gint group) gint group)
{ {
g_return_if_fail (EEK_IS_ELEMENT(element)); g_return_if_fail (EEK_IS_ELEMENT(element));
if (element->priv->group != group) {
element->priv->group = group; EekElementPrivate *priv = eek_element_get_instance_private (element);
if (priv->group != group) {
priv->group = group;
g_object_notify (G_OBJECT(element), "group"); g_object_notify (G_OBJECT(element), "group");
g_signal_emit (element, signals[SYMBOL_INDEX_CHANGED], 0, g_signal_emit (element, signals[SYMBOL_INDEX_CHANGED], 0,
group, element->priv->level); group, priv->level);
} }
} }
@ -509,11 +521,14 @@ eek_element_set_level (EekElement *element,
gint level) gint level)
{ {
g_return_if_fail (EEK_IS_ELEMENT(element)); g_return_if_fail (EEK_IS_ELEMENT(element));
if (element->priv->level != level) {
element->priv->level = level; EekElementPrivate *priv = eek_element_get_instance_private (element);
if (priv->level != level) {
priv->level = level;
g_object_notify (G_OBJECT(element), "level"); g_object_notify (G_OBJECT(element), "level");
g_signal_emit (element, signals[SYMBOL_INDEX_CHANGED], 0, g_signal_emit (element, signals[SYMBOL_INDEX_CHANGED], 0,
element->priv->group, level); priv->group, level);
} }
} }
@ -530,7 +545,10 @@ gint
eek_element_get_group (EekElement *element) eek_element_get_group (EekElement *element)
{ {
g_return_val_if_fail (EEK_IS_ELEMENT(element), -1); g_return_val_if_fail (EEK_IS_ELEMENT(element), -1);
return element->priv->group;
EekElementPrivate *priv = eek_element_get_instance_private (element);
return priv->group;
} }
/** /**
@ -546,5 +564,8 @@ gint
eek_element_get_level (EekElement *element) eek_element_get_level (EekElement *element)
{ {
g_return_val_if_fail (EEK_IS_ELEMENT(element), -1); g_return_val_if_fail (EEK_IS_ELEMENT(element), -1);
return element->priv->level;
EekElementPrivate *priv = eek_element_get_instance_private (element);
return priv->level;
} }

View File

@ -30,22 +30,7 @@
G_BEGIN_DECLS G_BEGIN_DECLS
#define EEK_TYPE_ELEMENT (eek_element_get_type()) #define EEK_TYPE_ELEMENT (eek_element_get_type())
#define EEK_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEK_TYPE_ELEMENT, EekElement)) G_DECLARE_DERIVABLE_TYPE (EekElement, eek_element, EEK, ELEMENT, GObject)
#define EEK_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEK_TYPE_ELEMENT, EekElementClass))
#define EEK_IS_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEK_TYPE_ELEMENT))
#define EEK_IS_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_ELEMENT))
#define EEK_ELEMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_ELEMENT, EekElementClass))
typedef struct _EekElementClass EekElementClass;
typedef struct _EekElementPrivate EekElementPrivate;
struct _EekElement
{
/*< private >*/
GObject parent;
EekElementPrivate *priv;
};
struct _EekElementClass struct _EekElementClass
{ {

View File

@ -23,18 +23,17 @@
* @short_description: a #GtkWidget displaying #EekKeyboard * @short_description: a #GtkWidget displaying #EekKeyboard
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */
#ifdef HAVE_LIBCANBERRA #ifdef HAVE_LIBCANBERRA
#include <canberra-gtk.h> #include <canberra-gtk.h>
#endif #endif
#include <math.h>
#include <string.h> #include <string.h>
#include "eek-gtk-keyboard.h" #include "eek-gtk-keyboard.h"
#include "eek-gtk-renderer.h" #include "eek-renderer.h"
#include "eek-keyboard.h" #include "eek-keyboard.h"
#include "eek-section.h" #include "eek-section.h"
#include "eek-key.h" #include "eek-key.h"
@ -46,26 +45,22 @@ enum {
PROP_LAST PROP_LAST
}; };
G_DEFINE_TYPE (EekGtkKeyboard, eek_gtk_keyboard, GTK_TYPE_DRAWING_AREA);
#define EEK_GTK_KEYBOARD_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_GTK_KEYBOARD, EekGtkKeyboardPrivate))
/* since 2.91.5 GDK_DRAWABLE was removed and gdk_cairo_create takes /* since 2.91.5 GDK_DRAWABLE was removed and gdk_cairo_create takes
GdkWindow as the argument */ GdkWindow as the argument */
#ifndef GDK_DRAWABLE #ifndef GDK_DRAWABLE
#define GDK_DRAWABLE(x) (x) #define GDK_DRAWABLE(x) (x)
#endif #endif
struct _EekGtkKeyboardPrivate typedef struct _EekGtkKeyboardPrivate
{ {
EekRenderer *renderer; EekRenderer *renderer;
EekKeyboard *keyboard; EekKeyboard *keyboard;
gulong key_locked_handler;
gulong key_unlocked_handler;
gulong symbol_index_changed_handler;
EekTheme *theme; EekTheme *theme;
};
GdkEventSequence *sequence; // unowned reference
} EekGtkKeyboardPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (EekGtkKeyboard, eek_gtk_keyboard, GTK_TYPE_DRAWING_AREA)
static void on_key_pressed (EekKey *key, static void on_key_pressed (EekKey *key,
EekGtkKeyboard *self); EekGtkKeyboard *self);
@ -106,7 +101,8 @@ static gboolean
eek_gtk_keyboard_real_draw (GtkWidget *self, eek_gtk_keyboard_real_draw (GtkWidget *self,
cairo_t *cr) cairo_t *cr)
{ {
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); EekGtkKeyboardPrivate *priv =
eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
GtkAllocation allocation; GtkAllocation allocation;
GList *list, *head; GList *list, *head;
@ -116,13 +112,15 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
PangoContext *pcontext; PangoContext *pcontext;
pcontext = gtk_widget_get_pango_context (self); pcontext = gtk_widget_get_pango_context (self);
priv->renderer = eek_gtk_renderer_new (priv->keyboard, pcontext, self); priv->renderer = eek_renderer_new (priv->keyboard, pcontext);
if (priv->theme) if (priv->theme)
eek_renderer_set_theme (priv->renderer, priv->theme); eek_renderer_set_theme (priv->renderer, priv->theme);
eek_renderer_set_allocation_size (priv->renderer, eek_renderer_set_allocation_size (priv->renderer,
allocation.width, allocation.width,
allocation.height); allocation.height);
eek_renderer_set_scale_factor (priv->renderer,
gtk_widget_get_scale_factor (self));
} }
eek_renderer_render_keyboard (priv->renderer, cr); eek_renderer_render_keyboard (priv->renderer, cr);
@ -148,7 +146,8 @@ static void
eek_gtk_keyboard_real_size_allocate (GtkWidget *self, eek_gtk_keyboard_real_size_allocate (GtkWidget *self,
GtkAllocation *allocation) GtkAllocation *allocation)
{ {
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); EekGtkKeyboardPrivate *priv =
eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
if (priv->renderer) if (priv->renderer)
eek_renderer_set_allocation_size (priv->renderer, eek_renderer_set_allocation_size (priv->renderer,
@ -161,8 +160,9 @@ eek_gtk_keyboard_real_size_allocate (GtkWidget *self,
static void depress(EekGtkKeyboard *self, static void depress(EekGtkKeyboard *self,
gdouble x, gdouble y, guint32 time) { gdouble x, gdouble y, guint32 time) {
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
EekKey *key = eek_renderer_find_key_by_position (priv->renderer, x, y); EekKey *key = eek_renderer_find_key_by_position (priv->renderer, x, y);
if (key) { if (key) {
eek_keyboard_press_key(priv->keyboard, key, time); eek_keyboard_press_key(priv->keyboard, key, time);
on_key_pressed(key, self); on_key_pressed(key, self);
@ -171,7 +171,7 @@ static void depress(EekGtkKeyboard *self,
static void drag(EekGtkKeyboard *self, static void drag(EekGtkKeyboard *self,
gdouble x, gdouble y, guint32 time) { gdouble x, gdouble y, guint32 time) {
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
EekKey *key = eek_renderer_find_key_by_position (priv->renderer, x, y); EekKey *key = eek_renderer_find_key_by_position (priv->renderer, x, y);
if (key) { if (key) {
@ -197,7 +197,7 @@ static void drag(EekGtkKeyboard *self,
} }
static void release(EekGtkKeyboard *self, guint32 time) { static void release(EekGtkKeyboard *self, guint32 time) {
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
GList *list = eek_keyboard_get_pressed_keys (priv->keyboard); GList *list = eek_keyboard_get_pressed_keys (priv->keyboard);
for (GList *head = list; head; head = g_list_next (head)) { for (GList *head = list; head; head = g_list_next (head)) {
@ -242,20 +242,23 @@ eek_gtk_keyboard_real_motion_notify_event (GtkWidget *self,
// Only one touch stream at a time allowed. Others will be completely ignored. // Only one touch stream at a time allowed. Others will be completely ignored.
static gboolean static gboolean
handle_touch_event (GtkWidget *widget, handle_touch_event (GtkWidget *widget,
GdkEventTouch *event) { GdkEventTouch *event)
EekGtkKeyboard *self = EEK_GTK_KEYBOARD(widget); {
EekGtkKeyboard *self = EEK_GTK_KEYBOARD (widget);
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
if (event->type == GDK_TOUCH_BEGIN) { if (event->type == GDK_TOUCH_BEGIN) {
if (self->sequence) { if (priv->sequence) {
// Ignore second and following touch points // Ignore second and following touch points
return FALSE; return FALSE;
} }
self->sequence = event->sequence; priv->sequence = event->sequence;
depress(self, event->x, event->y, event->time); depress(self, event->x, event->y, event->time);
return TRUE; return TRUE;
} }
if (self->sequence != event->sequence) { if (priv->sequence != event->sequence) {
return FALSE; return FALSE;
} }
@ -265,16 +268,16 @@ handle_touch_event (GtkWidget *widget,
if (event->type == GDK_TOUCH_END || event->type == GDK_TOUCH_CANCEL) { if (event->type == GDK_TOUCH_END || event->type == GDK_TOUCH_CANCEL) {
// TODO: can the event have different coords than the previous update event? // TODO: can the event have different coords than the previous update event?
release(self, event->time); release(self, event->time);
self->sequence = NULL; priv->sequence = NULL;
} }
return TRUE; return TRUE;
} }
static void static void
eek_gtk_keyboard_real_unmap (GtkWidget *self) eek_gtk_keyboard_real_unmap (GtkWidget *self)
{ {
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); EekGtkKeyboardPrivate *priv =
eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
if (priv->keyboard) { if (priv->keyboard) {
GList *list, *head; GList *list, *head;
@ -301,7 +304,9 @@ eek_gtk_keyboard_real_query_tooltip (GtkWidget *widget,
gboolean keyboard_tooltip, gboolean keyboard_tooltip,
GtkTooltip *tooltip) GtkTooltip *tooltip)
{ {
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget); EekGtkKeyboard *self = EEK_GTK_KEYBOARD (widget);
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
EekKey *key; EekKey *key;
key = eek_renderer_find_key_by_position (priv->renderer, key = eek_renderer_find_key_by_position (priv->renderer,
@ -322,18 +327,24 @@ static void
eek_gtk_keyboard_set_keyboard (EekGtkKeyboard *self, eek_gtk_keyboard_set_keyboard (EekGtkKeyboard *self,
EekKeyboard *keyboard) EekKeyboard *keyboard)
{ {
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
if (priv->keyboard == keyboard)
return;
if (priv->keyboard) {
g_signal_handlers_disconnect_by_data(priv->keyboard, self);
g_object_unref (priv->keyboard);
}
priv->keyboard = g_object_ref (keyboard); priv->keyboard = g_object_ref (keyboard);
priv->key_locked_handler = g_signal_connect (priv->keyboard, "key-locked",
g_signal_connect (priv->keyboard, "key-locked", G_CALLBACK(on_key_locked), self);
G_CALLBACK(on_key_locked), self); g_signal_connect (priv->keyboard, "key-unlocked",
priv->key_unlocked_handler = G_CALLBACK(on_key_unlocked), self);
g_signal_connect (priv->keyboard, "key-unlocked", g_signal_connect (priv->keyboard, "symbol-index-changed",
G_CALLBACK(on_key_unlocked), self); G_CALLBACK(on_symbol_index_changed), self);
priv->symbol_index_changed_handler =
g_signal_connect (priv->keyboard, "symbol-index-changed",
G_CALLBACK(on_symbol_index_changed), self);
} }
static void static void
@ -358,7 +369,8 @@ eek_gtk_keyboard_set_property (GObject *object,
static void static void
eek_gtk_keyboard_dispose (GObject *object) eek_gtk_keyboard_dispose (GObject *object)
{ {
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(object); EekGtkKeyboard *self = EEK_GTK_KEYBOARD (object);
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
if (priv->renderer) { if (priv->renderer) {
g_object_unref (priv->renderer); g_object_unref (priv->renderer);
@ -366,21 +378,9 @@ eek_gtk_keyboard_dispose (GObject *object)
} }
if (priv->keyboard) { if (priv->keyboard) {
if (g_signal_handler_is_connected (priv->keyboard,
priv->key_locked_handler))
g_signal_handler_disconnect (priv->keyboard,
priv->key_locked_handler);
if (g_signal_handler_is_connected (priv->keyboard,
priv->key_unlocked_handler))
g_signal_handler_disconnect (priv->keyboard,
priv->key_unlocked_handler);
if (g_signal_handler_is_connected (priv->keyboard,
priv->symbol_index_changed_handler))
g_signal_handler_disconnect (priv->keyboard,
priv->symbol_index_changed_handler);
GList *list, *head; GList *list, *head;
g_signal_handlers_disconnect_by_data(priv->keyboard, self);
list = eek_keyboard_get_pressed_keys (priv->keyboard); list = eek_keyboard_get_pressed_keys (priv->keyboard);
for (head = list; head; head = g_list_next (head)) { for (head = list; head; head = g_list_next (head)) {
g_log("squeek", G_LOG_LEVEL_DEBUG, "emit EekKey pressed"); g_log("squeek", G_LOG_LEVEL_DEBUG, "emit EekKey pressed");
@ -407,9 +407,6 @@ eek_gtk_keyboard_class_init (EekGtkKeyboardClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec; GParamSpec *pspec;
g_type_class_add_private (gobject_class,
sizeof (EekGtkKeyboardPrivate));
widget_class->realize = eek_gtk_keyboard_real_realize; widget_class->realize = eek_gtk_keyboard_real_realize;
widget_class->unmap = eek_gtk_keyboard_real_unmap; widget_class->unmap = eek_gtk_keyboard_real_unmap;
widget_class->draw = eek_gtk_keyboard_real_draw; widget_class->draw = eek_gtk_keyboard_real_draw;
@ -440,7 +437,7 @@ eek_gtk_keyboard_class_init (EekGtkKeyboardClass *klass)
static void static void
eek_gtk_keyboard_init (EekGtkKeyboard *self) eek_gtk_keyboard_init (EekGtkKeyboard *self)
{ {
self->priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); /* void */
} }
/** /**
@ -483,89 +480,94 @@ static void
render_pressed_key (GtkWidget *widget, render_pressed_key (GtkWidget *widget,
EekKey *key) EekKey *key)
{ {
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget); EekGtkKeyboard *self = EEK_GTK_KEYBOARD (widget);
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
EekBounds bounds, large_bounds; EekBounds bounds, large_bounds;
GdkWindow *window = gtk_widget_get_window (widget);
cairo_region_t *region = gdk_window_get_clip_region (window);
GdkDrawingContext *context = gdk_window_begin_draw_frame (window, region);
cairo_t *cr = gdk_drawing_context_get_cairo_context (context);
gdouble scale = eek_renderer_get_scale (priv->renderer);
eek_renderer_get_key_bounds (priv->renderer, key, &bounds, TRUE); eek_renderer_get_key_bounds (priv->renderer, key, &bounds, TRUE);
magnify_bounds (widget, &bounds, &large_bounds, 1.5); magnify_bounds (widget, &bounds, &large_bounds, 1.5);
GdkWindow *window = GDK_DRAWABLE (gtk_widget_get_window (widget));
cairo_region_t *region = gdk_window_get_clip_region (window);
GdkDrawingContext *context = gdk_window_begin_draw_frame(
window, region
);
cairo_t *cr = gdk_drawing_context_get_cairo_context(context);
cairo_save (cr); cairo_save (cr);
cairo_scale (cr, scale, scale);
cairo_translate (cr, bounds.x, bounds.y); cairo_translate (cr, bounds.x, bounds.y);
eek_renderer_render_key (priv->renderer, cr, key, 1.0, TRUE); eek_renderer_render_key (priv->renderer, cr, key, 1.0, TRUE);
cairo_restore (cr); cairo_restore (cr);
/*
cairo_save (cr); cairo_save (cr);
cairo_translate (cr, large_bounds.x, large_bounds.y); cairo_translate (cr, large_bounds.x, large_bounds.y);
eek_renderer_render_key (priv->renderer, cr, key, 1.5, TRUE); eek_renderer_render_key (priv->renderer, cr, key, 1.5, TRUE);
cairo_restore (cr); cairo_restore (cr);
*/
gdk_window_end_draw_frame (window, context);
gdk_window_end_draw_frame(window, context); cairo_region_destroy (region);
cairo_region_destroy(region);
} }
static void static void
render_locked_key (GtkWidget *widget, render_locked_key (GtkWidget *widget,
EekKey *key) EekKey *key)
{ {
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget); EekGtkKeyboard *self = EEK_GTK_KEYBOARD (widget);
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
EekBounds bounds; EekBounds bounds;
cairo_t *cr;
cr = gdk_cairo_create (GDK_DRAWABLE (gtk_widget_get_window (widget))); GdkWindow *window = gtk_widget_get_window (widget);
cairo_region_t *region = gdk_window_get_clip_region (window);
GdkDrawingContext *context = gdk_window_begin_draw_frame (window, region);
cairo_t *cr = gdk_drawing_context_get_cairo_context (context);
gdouble scale = eek_renderer_get_scale (priv->renderer);
eek_renderer_get_key_bounds (priv->renderer, key, &bounds, TRUE); eek_renderer_get_key_bounds (priv->renderer, key, &bounds, TRUE);
cairo_save (cr);
cairo_scale (cr, scale, scale);
cairo_translate (cr, bounds.x, bounds.y); cairo_translate (cr, bounds.x, bounds.y);
eek_renderer_render_key (priv->renderer, cr, key, 1.0, TRUE); eek_renderer_render_key (priv->renderer, cr, key, 1.0, TRUE);
cairo_restore (cr);
cairo_destroy (cr); gdk_window_end_draw_frame (window, context);
cairo_region_destroy (region);
} }
static void static void
render_released_key (GtkWidget *widget, render_released_key (GtkWidget *widget,
EekKey *key) EekKey *key)
{ {
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget); EekGtkKeyboard *self = EEK_GTK_KEYBOARD (widget);
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
EekBounds bounds, large_bounds; EekBounds bounds, large_bounds;
cairo_t *cr;
cr = gdk_cairo_create (GDK_DRAWABLE (gtk_widget_get_window (widget))); GdkWindow *window = gtk_widget_get_window (widget);
cairo_region_t *region = gdk_window_get_clip_region (window);
eek_renderer_get_key_bounds (priv->renderer, key, &bounds, TRUE); GdkDrawingContext *context = gdk_window_begin_draw_frame (window, region);
magnify_bounds (widget, &bounds, &large_bounds, 2.0); cairo_t *cr = gdk_drawing_context_get_cairo_context (context);
cairo_rectangle (cr,
large_bounds.x,
large_bounds.y,
large_bounds.width,
large_bounds.height);
cairo_rectangle (cr,
bounds.x,
bounds.y,
bounds.width,
bounds.height);
cairo_clip (cr);
eek_renderer_render_keyboard (priv->renderer, cr); eek_renderer_render_keyboard (priv->renderer, cr);
cairo_destroy (cr);
gdk_window_end_draw_frame (window, context);
cairo_region_destroy (region);
} }
static void static void
on_key_pressed (EekKey *key, on_key_pressed (EekKey *key,
EekGtkKeyboard *self) EekGtkKeyboard *self)
{ {
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
/* renderer may have not been set yet if the widget is a popup */ /* renderer may have not been set yet if the widget is a popup */
if (!priv->renderer) if (!priv->renderer)
return; return;
render_pressed_key (GTK_WIDGET(self), key); render_pressed_key (GTK_WIDGET(self), key);
gtk_widget_queue_draw (GTK_WIDGET(self));
#if HAVE_LIBCANBERRA #if HAVE_LIBCANBERRA
ca_gtk_play_for_widget (widget, 0, ca_gtk_play_for_widget (widget, 0,
@ -580,13 +582,14 @@ static void
on_key_released (EekKey *key, on_key_released (EekKey *key,
EekGtkKeyboard *self) EekGtkKeyboard *self)
{ {
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
/* renderer may have not been set yet if the widget is a popup */ /* renderer may have not been set yet if the widget is a popup */
if (!priv->renderer) if (!priv->renderer)
return; return;
render_released_key (GTK_WIDGET(self), key); render_released_key (GTK_WIDGET(self), key);
gtk_widget_queue_draw (GTK_WIDGET(self));
#if HAVE_LIBCANBERRA #if HAVE_LIBCANBERRA
ca_gtk_play_for_widget (widget, 0, ca_gtk_play_for_widget (widget, 0,
@ -603,13 +606,14 @@ on_key_locked (EekKeyboard *keyboard,
gpointer user_data) gpointer user_data)
{ {
GtkWidget *widget = user_data; GtkWidget *widget = user_data;
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget); EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (user_data);
/* renderer may have not been set yet if the widget is a popup */ /* renderer may have not been set yet if the widget is a popup */
if (!priv->renderer) if (!priv->renderer)
return; return;
render_locked_key (widget, key); render_locked_key (widget, key);
gtk_widget_queue_draw (widget);
} }
static void static void
@ -618,13 +622,14 @@ on_key_unlocked (EekKeyboard *keyboard,
gpointer user_data) gpointer user_data)
{ {
GtkWidget *widget = user_data; GtkWidget *widget = user_data;
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget); EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (user_data);
/* renderer may have not been set yet if the widget is a popup */ /* renderer may have not been set yet if the widget is a popup */
if (!priv->renderer) if (!priv->renderer)
return; return;
render_released_key (widget, key); render_released_key (widget, key);
gtk_widget_queue_draw (GTK_WIDGET(widget));
} }
static void static void
@ -642,11 +647,9 @@ void
eek_gtk_keyboard_set_theme (EekGtkKeyboard *keyboard, eek_gtk_keyboard_set_theme (EekGtkKeyboard *keyboard,
EekTheme *theme) EekTheme *theme)
{ {
EekGtkKeyboardPrivate *priv;
g_return_if_fail (EEK_IS_GTK_KEYBOARD(keyboard)); g_return_if_fail (EEK_IS_GTK_KEYBOARD(keyboard));
g_return_if_fail (EEK_IS_THEME(theme)); g_return_if_fail (EEK_IS_THEME(theme));
priv = EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard); EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (keyboard);
priv->theme = g_object_ref (theme); priv->theme = g_object_ref (theme);
} }

View File

@ -32,25 +32,7 @@
G_BEGIN_DECLS G_BEGIN_DECLS
#define EEK_TYPE_GTK_KEYBOARD (eek_gtk_keyboard_get_type()) #define EEK_TYPE_GTK_KEYBOARD (eek_gtk_keyboard_get_type())
#define EEK_GTK_KEYBOARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEK_TYPE_GTK_KEYBOARD, EekGtkKeyboard)) G_DECLARE_DERIVABLE_TYPE (EekGtkKeyboard, eek_gtk_keyboard, EEK, GTK_KEYBOARD, GtkDrawingArea)
#define EEK_GTK_KEYBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEK_TYPE_GTK_KEYBOARD, EekGtkKeyboardClass))
#define EEK_IS_GTK_KEYBOARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEK_TYPE_GTK_KEYBOARD))
#define EEK_IS_GTK_KEYBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_GTK_KEYBOARD))
#define EEK_GTK_KEYBOARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_GTK_KEYBOARD, EekGtkKeyboardClass))
typedef struct _EekGtkKeyboard EekGtkKeyboard;
typedef struct _EekGtkKeyboardClass EekGtkKeyboardClass;
typedef struct _EekGtkKeyboardPrivate EekGtkKeyboardPrivate;
struct _EekGtkKeyboard
{
/*< private >*/
GtkDrawingArea parent;
GdkEventSequence *sequence; // unowned reference
EekGtkKeyboardPrivate *priv;
};
struct _EekGtkKeyboardClass struct _EekGtkKeyboardClass
{ {

View File

@ -1,104 +0,0 @@
/*
* Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2011 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include <string.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "eek-gtk-renderer.h"
#include "eek-key.h"
G_DEFINE_TYPE (EekGtkRenderer, eek_gtk_renderer, EEK_TYPE_RENDERER);
static cairo_surface_t *
pixbuf_to_cairo_surface (GdkPixbuf *pixbuf)
{
cairo_surface_t *dummy_surface;
cairo_pattern_t *pattern;
cairo_surface_t *surface;
cairo_t *cr;
dummy_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
cr = cairo_create (dummy_surface);
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
pattern = cairo_get_source (cr);
cairo_pattern_get_surface (pattern, &surface);
cairo_surface_reference (surface);
cairo_destroy (cr);
cairo_surface_destroy (dummy_surface);
return surface;
}
static cairo_surface_t *
eek_gtk_renderer_real_get_icon_surface (EekRenderer *self,
const gchar *icon_name,
gint size)
{
GdkPixbuf *pixbuf;
GError *error;
cairo_surface_t *surface;
error = NULL;
pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
icon_name,
size,
0,
&error);
if (pixbuf == NULL) {
g_warning ("can't get icon pixbuf for %s: %s",
icon_name,
error->message);
g_error_free (error);
return NULL;
}
surface = pixbuf_to_cairo_surface (pixbuf);
g_object_unref (pixbuf);
return surface;
}
static void
eek_gtk_renderer_class_init (EekGtkRendererClass *klass)
{
EekRendererClass *renderer_class = EEK_RENDERER_CLASS (klass);
renderer_class->get_icon_surface = eek_gtk_renderer_real_get_icon_surface;
}
static void
eek_gtk_renderer_init (EekGtkRenderer *self)
{
}
EekRenderer *
eek_gtk_renderer_new (EekKeyboard *keyboard,
PangoContext *pcontext,
GtkWidget *widget)
{
return g_object_new (EEK_TYPE_GTK_RENDERER,
"keyboard", keyboard,
"pango-context", pcontext,
NULL);
}

View File

@ -1,61 +0,0 @@
/*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#ifndef EEK_GTK_RENDERER_H
#define EEK_GTK_RENDERER_H 1
#include <gtk/gtk.h>
#include "eek-renderer.h"
G_BEGIN_DECLS
#define EEK_TYPE_GTK_RENDERER (eek_gtk_renderer_get_type())
#define EEK_GTK_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEK_TYPE_GTK_RENDERER, EekGtkRenderer))
#define EEK_GTK_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEK_TYPE_GTK_RENDERER, EekGtkRendererClass))
#define EEK_IS_GTK_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEK_TYPE_GTK_RENDERER))
#define EEK_IS_GTK_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_GTK_RENDERER))
#define EEK_GTK_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_GTK_RENDERER, EekGtkRendererClass))
typedef struct _EekGtkRenderer EekGtkRenderer;
typedef struct _EekGtkRendererClass EekGtkRendererClass;
typedef struct _EekGtkRendererPrivate EekGtkRendererPrivate;
struct _EekGtkRenderer {
EekRenderer parent;
EekGtkRendererPrivate *priv;
};
struct _EekGtkRendererClass
{
EekRendererClass parent_class;
/*< private >*/
/* padding */
gpointer pdummy[24];
};
GType eek_gtk_renderer_get_type (void) G_GNUC_CONST;
EekRenderer *eek_gtk_renderer_new (EekKeyboard *keyboard,
PangoContext *pcontext,
GtkWidget *widget);
G_END_DECLS
#endif /* EEK_GTK_RENDERER_H */

View File

@ -25,9 +25,7 @@
* The #EekKeyClass class represents a key. * The #EekKeyClass class represents a key.
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */
#include <string.h> #include <string.h>
@ -54,13 +52,7 @@ enum {
static guint signals[LAST_SIGNAL] = { 0, }; static guint signals[LAST_SIGNAL] = { 0, };
G_DEFINE_TYPE (EekKey, eek_key, EEK_TYPE_ELEMENT); typedef struct _EekKeyPrivate
#define EEK_KEY_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_KEY, EekKeyPrivate))
struct _EekKeyPrivate
{ {
guint keycode; guint keycode;
EekSymbolMatrix *symbol_matrix; EekSymbolMatrix *symbol_matrix;
@ -69,12 +61,14 @@ struct _EekKeyPrivate
gulong oref; // UI outline reference gulong oref; // UI outline reference
gboolean is_pressed; gboolean is_pressed;
gboolean is_locked; gboolean is_locked;
}; } EekKeyPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (EekKey, eek_key, EEK_TYPE_ELEMENT)
static void static void
eek_key_real_locked (EekKey *self) eek_key_real_locked (EekKey *self)
{ {
EekKeyPrivate *priv = EEK_KEY_GET_PRIVATE(self); EekKeyPrivate *priv = eek_key_get_instance_private (self);
priv->is_locked = TRUE; priv->is_locked = TRUE;
#if DEBUG #if DEBUG
@ -85,7 +79,7 @@ eek_key_real_locked (EekKey *self)
static void static void
eek_key_real_unlocked (EekKey *self) eek_key_real_unlocked (EekKey *self)
{ {
EekKeyPrivate *priv = EEK_KEY_GET_PRIVATE(self); EekKeyPrivate *priv = eek_key_get_instance_private (self);
priv->is_locked = FALSE; priv->is_locked = FALSE;
#if DEBUG #if DEBUG
@ -96,8 +90,11 @@ eek_key_real_unlocked (EekKey *self)
static void static void
eek_key_finalize (GObject *object) eek_key_finalize (GObject *object)
{ {
EekKeyPrivate *priv = EEK_KEY_GET_PRIVATE(object); EekKey *self = EEK_KEY (object);
EekKeyPrivate *priv = eek_key_get_instance_private (self);
eek_symbol_matrix_free (priv->symbol_matrix); eek_symbol_matrix_free (priv->symbol_matrix);
G_OBJECT_CLASS (eek_key_parent_class)->finalize (object); G_OBJECT_CLASS (eek_key_parent_class)->finalize (object);
} }
@ -174,9 +171,6 @@ eek_key_class_init (EekKeyClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec; GParamSpec *pspec;
g_type_class_add_private (gobject_class,
sizeof (EekKeyPrivate));
gobject_class->set_property = eek_key_set_property; gobject_class->set_property = eek_key_set_property;
gobject_class->get_property = eek_key_get_property; gobject_class->get_property = eek_key_get_property;
gobject_class->finalize = eek_key_finalize; gobject_class->finalize = eek_key_finalize;
@ -285,9 +279,7 @@ eek_key_class_init (EekKeyClass *klass)
static void static void
eek_key_init (EekKey *self) eek_key_init (EekKey *self)
{ {
EekKeyPrivate *priv; EekKeyPrivate *priv = eek_key_get_instance_private (self);
priv = self->priv = EEK_KEY_GET_PRIVATE(self);
priv->symbol_matrix = eek_symbol_matrix_new (0, 0); priv->symbol_matrix = eek_symbol_matrix_new (0, 0);
} }
@ -307,7 +299,10 @@ eek_key_set_keycode (EekKey *key,
guint keycode) guint keycode)
{ {
g_return_if_fail (EEK_IS_KEY (key)); g_return_if_fail (EEK_IS_KEY (key));
key->priv->keycode = keycode;
EekKeyPrivate *priv = eek_key_get_instance_private (key);
priv->keycode = keycode;
} }
/** /**
@ -321,7 +316,10 @@ guint
eek_key_get_keycode (EekKey *key) eek_key_get_keycode (EekKey *key)
{ {
g_return_val_if_fail (EEK_IS_KEY (key), EEK_INVALID_KEYCODE); g_return_val_if_fail (EEK_IS_KEY (key), EEK_INVALID_KEYCODE);
return key->priv->keycode;
EekKeyPrivate *priv = eek_key_get_instance_private (key);
return priv->keycode;
} }
/** /**
@ -337,8 +335,10 @@ eek_key_set_symbol_matrix (EekKey *key,
{ {
g_return_if_fail (EEK_IS_KEY(key)); g_return_if_fail (EEK_IS_KEY(key));
eek_symbol_matrix_free (key->priv->symbol_matrix); EekKeyPrivate *priv = eek_key_get_instance_private (key);
key->priv->symbol_matrix = eek_symbol_matrix_copy (matrix);
eek_symbol_matrix_free (priv->symbol_matrix);
priv->symbol_matrix = eek_symbol_matrix_copy (matrix);
} }
/** /**
@ -352,7 +352,10 @@ EekSymbolMatrix *
eek_key_get_symbol_matrix (EekKey *key) eek_key_get_symbol_matrix (EekKey *key)
{ {
g_return_val_if_fail (EEK_IS_KEY(key), NULL); g_return_val_if_fail (EEK_IS_KEY(key), NULL);
return key->priv->symbol_matrix;
EekKeyPrivate *priv = eek_key_get_instance_private (key);
return priv->symbol_matrix;
} }
/** /**
@ -440,7 +443,7 @@ eek_key_get_symbol_at_index (EekKey *key,
gint fallback_group, gint fallback_group,
gint fallback_level) gint fallback_level)
{ {
EekKeyPrivate *priv = EEK_KEY_GET_PRIVATE(key); EekKeyPrivate *priv = eek_key_get_instance_private (key);
gint num_symbols; gint num_symbols;
g_return_val_if_fail (fallback_group >= 0, NULL); g_return_val_if_fail (fallback_group >= 0, NULL);
@ -492,12 +495,14 @@ eek_key_set_index (EekKey *key,
g_return_if_fail (0 <= column); g_return_if_fail (0 <= column);
g_return_if_fail (0 <= row); g_return_if_fail (0 <= row);
if (key->priv->column != column) { EekKeyPrivate *priv = eek_key_get_instance_private (key);
key->priv->column = column;
if (priv->column != column) {
priv->column = column;
g_object_notify (G_OBJECT(key), "column"); g_object_notify (G_OBJECT(key), "column");
} }
if (key->priv->row != row) { if (priv->row != row) {
key->priv->row = row; priv->row = row;
g_object_notify (G_OBJECT(key), "row"); g_object_notify (G_OBJECT(key), "row");
} }
} }
@ -518,10 +523,12 @@ eek_key_get_index (EekKey *key,
g_return_if_fail (EEK_IS_KEY(key)); g_return_if_fail (EEK_IS_KEY(key));
g_return_if_fail (column != NULL || row != NULL); g_return_if_fail (column != NULL || row != NULL);
EekKeyPrivate *priv = eek_key_get_instance_private (key);
if (column != NULL) if (column != NULL)
*column = key->priv->column; *column = priv->column;
if (row != NULL) if (row != NULL)
*row = key->priv->row; *row = priv->row;
} }
/** /**
@ -536,8 +543,11 @@ eek_key_set_oref (EekKey *key,
guint oref) guint oref)
{ {
g_return_if_fail (EEK_IS_KEY(key)); g_return_if_fail (EEK_IS_KEY(key));
if (key->priv->oref != oref) {
key->priv->oref = oref; EekKeyPrivate *priv = eek_key_get_instance_private (key);
if (priv->oref != oref) {
priv->oref = oref;
g_object_notify (G_OBJECT(key), "oref"); g_object_notify (G_OBJECT(key), "oref");
} }
} }
@ -553,7 +563,10 @@ guint
eek_key_get_oref (EekKey *key) eek_key_get_oref (EekKey *key)
{ {
g_return_val_if_fail (EEK_IS_KEY (key), 0); g_return_val_if_fail (EEK_IS_KEY (key), 0);
return key->priv->oref;
EekKeyPrivate *priv = eek_key_get_instance_private (key);
return priv->oref;
} }
/** /**
@ -566,7 +579,10 @@ gboolean
eek_key_is_pressed (EekKey *key) eek_key_is_pressed (EekKey *key)
{ {
g_return_val_if_fail (EEK_IS_KEY(key), FALSE); g_return_val_if_fail (EEK_IS_KEY(key), FALSE);
return key->priv->is_pressed;
EekKeyPrivate *priv = eek_key_get_instance_private (key);
return priv->is_pressed;
} }
/** /**
@ -579,11 +595,25 @@ gboolean
eek_key_is_locked (EekKey *key) eek_key_is_locked (EekKey *key)
{ {
g_return_val_if_fail (EEK_IS_KEY(key), FALSE); g_return_val_if_fail (EEK_IS_KEY(key), FALSE);
return key->priv->is_locked;
EekKeyPrivate *priv = eek_key_get_instance_private (key);
return priv->is_locked;
} }
void eek_key_set_pressed(EekKey *key, gboolean value) void eek_key_set_pressed(EekKey *key, gboolean value)
{ {
g_return_if_fail (EEK_IS_KEY(key)); g_return_if_fail (EEK_IS_KEY(key));
key->priv->is_pressed = value;
EekKeyPrivate *priv = eek_key_get_instance_private (key);
priv->is_pressed = value;
}
gboolean
eek_key_has_label(EekKey *key)
{
EekSymbol *symbol = eek_key_get_symbol(key);
return (eek_symbol_get_label(symbol) != NULL) ||
(eek_symbol_get_icon_name(symbol) != NULL);
} }

View File

@ -31,31 +31,7 @@
G_BEGIN_DECLS G_BEGIN_DECLS
#define EEK_TYPE_KEY (eek_key_get_type()) #define EEK_TYPE_KEY (eek_key_get_type())
#define EEK_KEY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEK_TYPE_KEY, EekKey)) G_DECLARE_DERIVABLE_TYPE(EekKey, eek_key, EEK, KEY, EekElement)
#define EEK_KEY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEK_TYPE_KEY, EekKeyClass))
#define EEK_IS_KEY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEK_TYPE_KEY))
#define EEK_IS_KEY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_KEY))
#define EEK_KEY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_KEY, EekKeyClass))
typedef struct _EekKeyClass EekKeyClass;
typedef struct _EekKeyPrivate EekKeyPrivate;
/**
* EekKey:
*
* Contains information about the state of a key.
* TODO: rewrite as a plain struct
*
* The #EekKey structure contains only private data and should only be
* accessed using the provided API.
*/
struct _EekKey
{
/*< private >*/
EekElement parent;
EekKeyPrivate *priv;
};
/** /**
* EekKeyClass: * EekKeyClass:
@ -113,5 +89,7 @@ gboolean eek_key_is_locked (EekKey *key);
void eek_key_set_pressed (EekKey *key, void eek_key_set_pressed (EekKey *key,
gboolean value); gboolean value);
gboolean eek_key_has_label (EekKey *key);
G_END_DECLS G_END_DECLS
#endif /* EEK_KEY_H */ #endif /* EEK_KEY_H */

View File

@ -17,9 +17,7 @@
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */
#include <math.h> #include <math.h>
#include <pango/pangocairo.h> #include <pango/pangocairo.h>

View File

@ -27,9 +27,8 @@
* of one or more sections of the #EekSectionClass class. * of one or more sections of the #EekSectionClass class.
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */ #include <glib/gprintf.h>
#include "eek-keyboard.h" #include "eek-keyboard.h"
#include "eek-marshalers.h" #include "eek-marshalers.h"
@ -38,6 +37,7 @@
#include "eek-symbol.h" #include "eek-symbol.h"
#include "eek-enumtypes.h" #include "eek-enumtypes.h"
#include "eekboard/key-emitter.h" #include "eekboard/key-emitter.h"
#include "keymap.h"
enum { enum {
PROP_0, PROP_0,
@ -53,9 +53,14 @@ enum {
LAST_SIGNAL LAST_SIGNAL
}; };
static guint signals[LAST_SIGNAL] = { 0, }; enum {
VIEW_LETTERS_LOWER,
VIEW_LETTERS_UPPER,
VIEW_NUMBERS,
VIEW_SYMBOLS
};
G_DEFINE_TYPE (EekKeyboard, eek_keyboard, EEK_TYPE_CONTAINER); static guint signals[LAST_SIGNAL] = { 0, };
#define EEK_KEYBOARD_GET_PRIVATE(obj) \ #define EEK_KEYBOARD_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_KEYBOARD, EekKeyboardPrivate)) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_KEYBOARD, EekKeyboardPrivate))
@ -65,16 +70,21 @@ struct _EekKeyboardPrivate
EekLayout *layout; EekLayout *layout;
EekModifierBehavior modifier_behavior; EekModifierBehavior modifier_behavior;
EekModifierType modifiers; EekModifierType modifiers;
unsigned int old_level;
GList *pressed_keys; GList *pressed_keys;
GList *locked_keys; GList *locked_keys;
GArray *outline_array; GArray *outline_array;
GHashTable *keycodes;
/* Map key names to key objects: */
GHashTable *names;
/* modifiers dynamically assigned at run time */ /* modifiers dynamically assigned at run time */
EekModifierType num_lock_mask; EekModifierType num_lock_mask;
EekModifierType alt_gr_mask; EekModifierType alt_gr_mask;
}; };
G_DEFINE_TYPE_WITH_PRIVATE (EekKeyboard, eek_keyboard, EEK_TYPE_CONTAINER);
G_DEFINE_BOXED_TYPE(EekModifierKey, eek_modifier_key, G_DEFINE_BOXED_TYPE(EekModifierKey, eek_modifier_key,
eek_modifier_key_copy, eek_modifier_key_free); eek_modifier_key_copy, eek_modifier_key_free);
@ -121,9 +131,9 @@ section_child_added_cb (EekContainer *container,
EekElement *element, EekElement *element,
EekKeyboard *keyboard) EekKeyboard *keyboard)
{ {
guint keycode = eek_key_get_keycode (EEK_KEY(element)); const gchar *name = eek_element_get_name(element);
g_hash_table_insert (keyboard->priv->keycodes, g_hash_table_insert (keyboard->priv->names,
GUINT_TO_POINTER(keycode), (gpointer)name,
element); element);
} }
@ -132,9 +142,9 @@ section_child_removed_cb (EekContainer *container,
EekElement *element, EekElement *element,
EekKeyboard *keyboard) EekKeyboard *keyboard)
{ {
guint keycode = eek_key_get_keycode (EEK_KEY(element)); const gchar *name = eek_element_get_name(element);
g_hash_table_remove (keyboard->priv->keycodes, g_hash_table_remove (keyboard->priv->names,
GUINT_TO_POINTER(keycode)); name);
} }
static EekSection * static EekSection *
@ -203,16 +213,61 @@ eek_keyboard_get_property (GObject *object,
} }
static void static void
set_level_from_modifiers (EekKeyboard *self) set_level_from_modifiers (EekKeyboard *self, EekKey *key)
{ {
EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(self); EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(self);
gint level = 0;
if (priv->modifiers & priv->alt_gr_mask) /* The levels are: 0 Letters, 1 Upper case letters, 2 Numbers, 3 Symbols */
level |= 2;
if (priv->modifiers & EEK_SHIFT_MASK) /* Use the numbers/letters bit from the old level */
level |= 1; gint level = priv->old_level & 2;
/* Handle non-emitting keys */
if (key) {
const gchar *name = eek_element_get_name(EEK_ELEMENT(key));
if (g_strcmp0(name, "ABC123") == 0)
level ^= 2;
}
level |= ((priv->modifiers & EEK_SHIFT_MASK) ? 1 : 0);
switch (priv->old_level) {
case VIEW_LETTERS_UPPER:
{
/* Redirect upper case letters to numbers instead of symbols, clearing
the shift modifier to keep the modifiers in sync with the level */
if (level == VIEW_SYMBOLS) {
level = VIEW_NUMBERS;
priv->modifiers &= ~EEK_SHIFT_MASK;
}
break;
}
case VIEW_SYMBOLS:
{
/* Redirect symbols to lower case letters instead of upper case,
clearing the shift modifier to keep the modifiers in sync with the
level */
if (level == VIEW_LETTERS_UPPER) {
level = VIEW_LETTERS_LOWER;
priv->modifiers &= ~EEK_SHIFT_MASK;
}
break;
}
case VIEW_LETTERS_LOWER: /* Direct transitions between views */
case VIEW_NUMBERS:
default:
break;
}
if (level == VIEW_NUMBERS || level == VIEW_SYMBOLS)
priv->modifier_behavior = EEK_MODIFIER_BEHAVIOR_LOCK;
else
priv->modifier_behavior = EEK_MODIFIER_BEHAVIOR_LATCH;
priv->old_level = level;
eek_element_set_level (EEK_ELEMENT(self), level); eek_element_set_level (EEK_ELEMENT(self), level);
eek_layout_update_layout(self);
} }
static void static void
@ -267,7 +322,7 @@ void eek_keyboard_press_key(EekKeyboard *keyboard, EekKey *key, guint32 timestam
EekModifierType modifier = eek_symbol_get_modifier_mask (symbol); EekModifierType modifier = eek_symbol_get_modifier_mask (symbol);
if (priv->modifier_behavior == EEK_MODIFIER_BEHAVIOR_NONE) { if (priv->modifier_behavior == EEK_MODIFIER_BEHAVIOR_NONE) {
set_modifiers_with_key (keyboard, key, priv->modifiers | modifier); set_modifiers_with_key (keyboard, key, priv->modifiers | modifier);
set_level_from_modifiers (keyboard); set_level_from_modifiers (keyboard, key);
} }
// "Borrowed" from eek-context-service; doesn't influence the state but forwards the event // "Borrowed" from eek-context-service; doesn't influence the state but forwards the event
@ -316,7 +371,7 @@ void eek_keyboard_release_key( EekKeyboard *keyboard,
(priv->modifiers ^ modifier) & modifier); (priv->modifiers ^ modifier) & modifier);
break; break;
} }
set_level_from_modifiers (keyboard); set_level_from_modifiers (keyboard, key);
// "Borrowed" from eek-context-service; doesn't influence the state but forwards the event // "Borrowed" from eek-context-service; doesn't influence the state but forwards the event
@ -349,7 +404,7 @@ eek_keyboard_finalize (GObject *object)
g_list_free_full (priv->locked_keys, g_list_free_full (priv->locked_keys,
(GDestroyNotify) eek_modifier_key_free); (GDestroyNotify) eek_modifier_key_free);
g_hash_table_destroy (priv->keycodes); g_hash_table_destroy (priv->names);
for (i = 0; i < priv->outline_array->len; i++) { for (i = 0; i < priv->outline_array->len; i++) {
EekOutline *outline = &g_array_index (priv->outline_array, EekOutline *outline = &g_array_index (priv->outline_array,
@ -390,9 +445,6 @@ eek_keyboard_class_init (EekKeyboardClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec; GParamSpec *pspec;
g_type_class_add_private (gobject_class,
sizeof (EekKeyboardPrivate));
klass->create_section = eek_keyboard_real_create_section; klass->create_section = eek_keyboard_real_create_section;
/* signals */ /* signals */
@ -480,8 +532,9 @@ eek_keyboard_init (EekKeyboard *self)
self->priv = EEK_KEYBOARD_GET_PRIVATE(self); self->priv = EEK_KEYBOARD_GET_PRIVATE(self);
self->priv->modifier_behavior = EEK_MODIFIER_BEHAVIOR_NONE; self->priv->modifier_behavior = EEK_MODIFIER_BEHAVIOR_NONE;
self->priv->outline_array = g_array_new (FALSE, TRUE, sizeof (EekOutline)); self->priv->outline_array = g_array_new (FALSE, TRUE, sizeof (EekOutline));
self->priv->keycodes = g_hash_table_new (g_direct_hash, g_direct_equal); self->priv->names = g_hash_table_new (g_str_hash, g_str_equal);
eek_element_set_symbol_index (EEK_ELEMENT(self), 0, 0); eek_element_set_symbol_index (EEK_ELEMENT(self), 0, 0);
self->scale = 1.0;
} }
/** /**
@ -500,20 +553,20 @@ eek_keyboard_create_section (EekKeyboard *keyboard)
} }
/** /**
* eek_keyboard_find_key_by_keycode: * eek_keyboard_find_key_by_name:
* @keyboard: an #EekKeyboard * @keyboard: an #EekKeyboard
* @keycode: a keycode * @name: a key name
* *
* Find an #EekKey whose keycode is @keycode. * Find an #EekKey whose name is @name.
* Return value: (transfer none): #EekKey whose keycode is @keycode * Return value: (transfer none): #EekKey whose name is @name
*/ */
EekKey * EekKey *
eek_keyboard_find_key_by_keycode (EekKeyboard *keyboard, eek_keyboard_find_key_by_name (EekKeyboard *keyboard,
guint keycode) const gchar *name)
{ {
g_return_val_if_fail (EEK_IS_KEYBOARD(keyboard), NULL); g_return_val_if_fail (EEK_IS_KEYBOARD(keyboard), NULL);
return g_hash_table_lookup (keyboard->priv->keycodes, return g_hash_table_lookup (keyboard->priv->names,
GUINT_TO_POINTER(keycode)); name);
} }
/** /**
@ -585,7 +638,7 @@ eek_keyboard_set_modifiers (EekKeyboard *keyboard,
{ {
g_return_if_fail (EEK_IS_KEYBOARD(keyboard)); g_return_if_fail (EEK_IS_KEYBOARD(keyboard));
keyboard->priv->modifiers = modifiers; keyboard->priv->modifiers = modifiers;
set_level_from_modifiers (keyboard); set_level_from_modifiers (keyboard, NULL);
} }
/** /**
@ -747,3 +800,93 @@ eek_keyboard_get_locked_keys (EekKeyboard *keyboard)
g_return_val_if_fail (EEK_IS_KEYBOARD(keyboard), NULL); g_return_val_if_fail (EEK_IS_KEYBOARD(keyboard), NULL);
return g_list_copy (keyboard->priv->locked_keys); return g_list_copy (keyboard->priv->locked_keys);
} }
/**
* eek_keyboard_get_keymap:
* @keyboard: an #EekKeyboard
*
* Get the keymap for the keyboard.
* Returns: a string containing the XKB keymap.
*/
gchar *
eek_keyboard_get_keymap(EekKeyboard *keyboard)
{
/* Start the keycodes and symbols sections with their respective headers. */
gchar *keycodes = g_strdup(keymap_keycodes_header);
gchar *symbols = g_strdup(keymap_symbols_header);
/* Iterate over the keys in the name-to-key hash table. */
GHashTableIter iter;
gpointer key_name, key_ptr;
g_hash_table_iter_init(&iter, keyboard->priv->names);
while (g_hash_table_iter_next(&iter, &key_name, &key_ptr)) {
gchar *current, *line;
EekKey *key = EEK_KEY(key_ptr);
int keycode = eek_key_get_keycode(key);
/* Don't include invalid keycodes in the keymap. */
if (keycode == EEK_INVALID_KEYCODE)
continue;
/* Append a key name-to-keycode definition to the keycodes section. */
current = keycodes;
line = g_strdup_printf(" <%s> = %i;\n", (char *)key_name, keycode);
keycodes = g_strconcat(current, line, NULL);
g_free(line);
g_free(current);
/* Find the symbols associated with the key. */
EekSymbolMatrix *matrix = eek_key_get_symbol_matrix(key);
EekSymbol *syms[4];
int i, j;
/* Get the symbols for all the levels defined for the key, then
pad it out with the first symbol for all levels up to the fourth. */
for (i = 0; i < matrix->num_levels; ++i)
syms[i] = eek_symbol_matrix_get_symbol(matrix, 0, i);
while (i < 4) {
syms[i] = eek_symbol_matrix_get_symbol(matrix, 0, 0);
i++;
}
/* The four levels are split into two groups in the keymap.
Generate strings for each of these groups, where an empty group is
treated specially. */
gchar *groups[2];
for (i = 0, j = 0; i < 2; ++i, j += 2) {
if (syms[j] && syms[j + 1])
groups[i] = g_strjoin(", ", eek_symbol_get_name(syms[j]),
eek_symbol_get_name(syms[j + 1]),
NULL);
else
groups[i] = "";
}
/* Append a key definition to the symbols section. */
current = symbols;
line = g_strdup_printf(" key <%s> { [ %s ], [ %s ] };\n",
(char *)key_name, groups[0], groups[1]);
g_free(groups[0]);
g_free(groups[1]);
symbols = g_strconcat(current, line, NULL);
g_free(line);
g_free(current);
}
/* Assemble the keymap file from the header, sections and footer. */
gchar *keymap = g_strconcat(keymap_header,
keycodes, " };\n\n",
symbols, " };\n\n",
keymap_footer, NULL);
g_free(keycodes);
g_free(symbols);
return keymap;
}

View File

@ -62,6 +62,7 @@ struct _EekKeyboard
struct xkb_keymap *keymap; struct xkb_keymap *keymap;
int keymap_fd; // keymap formatted as XKB string int keymap_fd; // keymap formatted as XKB string
size_t keymap_len; // length of the data inside keymap_fd size_t keymap_len; // length of the data inside keymap_fd
double scale;
EekboardContextService *manager; // unowned reference EekboardContextService *manager; // unowned reference
}; };
@ -69,8 +70,8 @@ struct _EekKeyboard
/** /**
* EekKeyboardClass: * EekKeyboardClass:
* @create_section: virtual function for creating a section * @create_section: virtual function for creating a section
* @find_key_by_keycode: virtual function for finding a key in the * @find_key_by_name: virtual function for finding a key in the
* keyboard by keycode * keyboard by name
* @key_pressed: class handler for #EekKeyboard::key-pressed signal * @key_pressed: class handler for #EekKeyboard::key-pressed signal
* @key_released: class handler for #EekKeyboard::key-released signal * @key_released: class handler for #EekKeyboard::key-released signal
* @key_locked: class handler for #EekKeyboard::key-locked signal * @key_locked: class handler for #EekKeyboard::key-locked signal
@ -89,8 +90,8 @@ struct _EekKeyboardClass
/*< public >*/ /*< public >*/
EekSection *(* create_section) (EekKeyboard *self); EekSection *(* create_section) (EekKeyboard *self);
EekKey *(* find_key_by_keycode) (EekKeyboard *self, EekKey *(* find_key_by_name) (EekKeyboard *self,
guint keycode); const gchar *name);
/*< private >*/ /*< private >*/
/* obsolete members moved to EekElement */ /* obsolete members moved to EekElement */
@ -155,9 +156,9 @@ EekModifierType eek_keyboard_get_modifiers
EekSection *eek_keyboard_create_section EekSection *eek_keyboard_create_section
(EekKeyboard *keyboard); (EekKeyboard *keyboard);
EekKey *eek_keyboard_find_key_by_keycode EekKey *eek_keyboard_find_key_by_name
(EekKeyboard *keyboard, (EekKeyboard *keyboard,
guint keycode); const gchar *name);
guint eek_keyboard_add_outline guint eek_keyboard_add_outline
(EekKeyboard *keyboard, (EekKeyboard *keyboard,
@ -194,5 +195,8 @@ void eek_modifier_key_free
void eek_keyboard_press_key(EekKeyboard *keyboard, EekKey *key, guint32 timestamp); void eek_keyboard_press_key(EekKeyboard *keyboard, EekKey *key, guint32 timestamp);
void eek_keyboard_release_key(EekKeyboard *keyboard, EekKey *key, guint32 timestamp); void eek_keyboard_release_key(EekKeyboard *keyboard, EekKey *key, guint32 timestamp);
gchar * eek_keyboard_get_keymap
(EekKeyboard *keyboard);
G_END_DECLS G_END_DECLS
#endif /* EEK_KEYBOARD_H */ #endif /* EEK_KEYBOARD_H */

View File

@ -23,9 +23,7 @@
* @short_description: an #EekSymbol represents an X keysym * @short_description: an #EekSymbol represents an X keysym
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@ -50,9 +48,10 @@
#define EEK_KEYSYM_Hyper_L 0xffed #define EEK_KEYSYM_Hyper_L 0xffed
#define EEK_KEYSYM_Hyper_R 0xffee #define EEK_KEYSYM_Hyper_R 0xffee
struct _EekKeysymPrivate { typedef struct _EekKeysymPrivate
{
guint xkeysym; guint xkeysym;
}; } EekKeysymPrivate;
struct _EekKeysymEntry { struct _EekKeysymEntry {
guint xkeysym; guint xkeysym;
@ -68,12 +67,11 @@ typedef struct _EekKeysymEntry EekKeysymEntry;
static void eek_serializable_iface_init (EekSerializableIface *iface); static void eek_serializable_iface_init (EekSerializableIface *iface);
G_DEFINE_TYPE_WITH_CODE (EekKeysym, eek_keysym, EEK_TYPE_SYMBOL, G_DEFINE_TYPE_EXTENDED (EekKeysym, eek_keysym, EEK_TYPE_SYMBOL,
G_IMPLEMENT_INTERFACE (EEK_TYPE_SERIALIZABLE, 0, /* GTypeFlags */
eek_serializable_iface_init)); G_ADD_PRIVATE (EekKeysym)
G_IMPLEMENT_INTERFACE (EEK_TYPE_SERIALIZABLE,
#define EEK_KEYSYM_GET_PRIVATE(obj) \ eek_serializable_iface_init))
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_KEYSYM, EekKeysymPrivate))
static EekSerializableIface *eek_keysym_parent_serializable_iface; static EekSerializableIface *eek_keysym_parent_serializable_iface;
@ -81,7 +79,8 @@ static void
eek_keysym_real_serialize (EekSerializable *self, eek_keysym_real_serialize (EekSerializable *self,
GVariantBuilder *builder) GVariantBuilder *builder)
{ {
EekKeysymPrivate *priv = EEK_KEYSYM_GET_PRIVATE(self); EekKeysymPrivate *priv = eek_keysym_get_instance_private (
EEK_KEYSYM(self));
eek_keysym_parent_serializable_iface->serialize (self, builder); eek_keysym_parent_serializable_iface->serialize (self, builder);
@ -93,7 +92,8 @@ eek_keysym_real_deserialize (EekSerializable *self,
GVariant *variant, GVariant *variant,
gsize index) gsize index)
{ {
EekKeysymPrivate *priv = EEK_KEYSYM_GET_PRIVATE(self); EekKeysymPrivate *priv = eek_keysym_get_instance_private (
EEK_KEYSYM(self));
index = eek_keysym_parent_serializable_iface->deserialize (self, index = eek_keysym_parent_serializable_iface->deserialize (self,
variant, variant,
@ -200,15 +200,13 @@ get_modifier_mask (guint xkeysym)
static void static void
eek_keysym_class_init (EekKeysymClass *klass) eek_keysym_class_init (EekKeysymClass *klass)
{ {
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); /* void */
g_type_class_add_private (gobject_class, sizeof (EekKeysymPrivate));
} }
static void static void
eek_keysym_init (EekKeysym *self) eek_keysym_init (EekKeysym *self)
{ {
self->priv = EEK_KEYSYM_GET_PRIVATE(self); /* void */
} }
/** /**
@ -291,7 +289,7 @@ eek_keysym_new_with_modifier (guint xkeysym,
g_slice_free (EekKeysymEntry, unichar_entry); g_slice_free (EekKeysymEntry, unichar_entry);
} }
priv = EEK_KEYSYM_GET_PRIVATE(keysym); priv = eek_keysym_get_instance_private (keysym);
priv->xkeysym = xkeysym; priv->xkeysym = xkeysym;
return keysym; return keysym;
@ -345,6 +343,6 @@ eek_keysym_get_xkeysym (EekKeysym *keysym)
EekKeysymPrivate *priv; EekKeysymPrivate *priv;
g_assert (EEK_IS_KEYSYM(keysym)); g_assert (EEK_IS_KEYSYM(keysym));
priv = EEK_KEYSYM_GET_PRIVATE(keysym); priv = eek_keysym_get_instance_private (keysym);
return priv->xkeysym; return priv->xkeysym;
} }

View File

@ -38,27 +38,7 @@ G_BEGIN_DECLS
#define EEK_INVALID_KEYSYM (0) #define EEK_INVALID_KEYSYM (0)
#define EEK_TYPE_KEYSYM (eek_keysym_get_type()) #define EEK_TYPE_KEYSYM (eek_keysym_get_type())
#define EEK_KEYSYM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEK_TYPE_KEYSYM, EekKeysym)) G_DECLARE_DERIVABLE_TYPE (EekKeysym, eek_keysym, EEK, KEYSYM, EekSymbol)
#define EEK_KEYSYM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEK_TYPE_KEYSYM, EekKeysymClass))
#define EEK_IS_KEYSYM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEK_TYPE_KEYSYM))
#define EEK_IS_KEYSYM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_KEYSYM))
#define EEK_KEYSYM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_KEYSYM, EekKeysymClass))
typedef struct _EekKeysymClass EekKeysymClass;
typedef struct _EekKeysymPrivate EekKeysymPrivate;
/**
* EekKeysym:
*
* The #EekKeysym structure contains only private data and should only
* be accessed using the provided API.
*/
struct _EekKeysym {
/*< private >*/
EekSymbol parent;
EekKeysymPrivate *priv;
};
struct _EekKeysymClass { struct _EekKeysymClass {
/*< private >*/ /*< private >*/

View File

@ -26,15 +26,13 @@
* arranges keyboard elements. * arranges keyboard elements.
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */
#include "eek-layout.h" #include "eek-layout.h"
#include "eek-keyboard.h" #include "eek-keyboard.h"
#include "eekboard/eekboard-context-service.h" #include "eekboard/eekboard-context-service.h"
G_DEFINE_ABSTRACT_TYPE (EekLayout, eek_layout, G_TYPE_OBJECT); G_DEFINE_ABSTRACT_TYPE (EekLayout, eek_layout, G_TYPE_OBJECT)
static void static void
eek_layout_class_init (EekLayoutClass *klass) eek_layout_class_init (EekLayoutClass *klass)
@ -69,3 +67,70 @@ eek_keyboard_new (EekboardContextService *manager,
initial_width, initial_width,
initial_height); initial_height);
} }
const double section_spacing = 7.0;
struct place_data {
double desired_width;
double current_offset;
EekKeyboard *keyboard;
};
static void
section_placer(EekElement *element, gpointer user_data)
{
struct place_data *data = (struct place_data*)user_data;
EekBounds section_bounds = {0};
eek_element_get_bounds(element, &section_bounds);
section_bounds.width = data->desired_width;
eek_element_set_bounds(element, &section_bounds);
// Sections are rows now. Gather up all the keys and adjust their bounds.
eek_section_place_keys(EEK_SECTION(element), EEK_KEYBOARD(data->keyboard));
eek_element_get_bounds(element, &section_bounds);
section_bounds.y = data->current_offset;
eek_element_set_bounds(element, &section_bounds);
data->current_offset += section_bounds.height + section_spacing;
}
static void
section_counter(EekElement *element, gpointer user_data) {
double *total_height = user_data;
EekBounds section_bounds = {0};
eek_element_get_bounds(element, &section_bounds);
*total_height += section_bounds.height + section_spacing;
}
void
eek_layout_place_sections(EekKeyboard *keyboard)
{
/* Order rows */
// This needs to be done after outlines, because outlines define key sizes
// TODO: do this only for rows without bounds
// The keyboard width is given by the user via screen size. The height will be given dynamically.
// TODO: calculate max line width beforehand for button centering. Leave keyboard centering to the renderer later
EekBounds keyboard_bounds = {0};
eek_element_get_bounds(EEK_ELEMENT(keyboard), &keyboard_bounds);
struct place_data placer_data = {
.desired_width = keyboard_bounds.width,
.current_offset = 0,
.keyboard = keyboard,
};
eek_container_foreach_child(EEK_CONTAINER(keyboard), section_placer, &placer_data);
double total_height = 0;
eek_container_foreach_child(EEK_CONTAINER(keyboard), section_counter, &total_height);
keyboard_bounds.height = total_height;
eek_element_set_bounds(EEK_ELEMENT(keyboard), &keyboard_bounds);
}
void
eek_layout_update_layout(EekKeyboard *keyboard)
{
eek_layout_place_sections(keyboard);
}

View File

@ -31,20 +31,7 @@
G_BEGIN_DECLS G_BEGIN_DECLS
#define EEK_TYPE_LAYOUT (eek_layout_get_type()) #define EEK_TYPE_LAYOUT (eek_layout_get_type())
#define EEK_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEK_TYPE_LAYOUT, EekLayout)) G_DECLARE_DERIVABLE_TYPE (EekLayout, eek_layout, EEK, LAYOUT, GObject)
#define EEK_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEK_TYPE_LAYOUT, EekLayoutClass))
#define EEK_IS_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEK_TYPE_LAYOUT))
#define EEK_IS_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_LAYOUT))
#define EEK_LAYOUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_LAYOUT, EekLayoutClass))
typedef struct _EekLayoutClass EekLayoutClass;
typedef struct _EekLayout EekLayout;
struct _EekLayout
{
/*< private >*/
GObject parent;
};
/** /**
* EekLayoutClass: * EekLayoutClass:
@ -68,5 +55,9 @@ struct _EekLayoutClass
GType eek_layout_get_type (void) G_GNUC_CONST; GType eek_layout_get_type (void) G_GNUC_CONST;
void eek_layout_place_sections(EekKeyboard *keyboard);
void eek_layout_update_layout(EekKeyboard *keyboard);
G_END_DECLS G_END_DECLS
#endif /* EEK_LAYOUT_H */ #endif /* EEK_LAYOUT_H */

View File

@ -1,29 +1,29 @@
/* /*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org> * Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc. * Copyright (C) 2010-2011 Red Hat, Inc.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License * modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of * as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version. * the License, or (at your option) any later version.
* *
* This library is distributed in the hope that it will be useful, but * This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA * 02110-1301 USA
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gtk/gtk.h>
#include "eek-key.h" #include "eek-key.h"
#include "eek-section.h" #include "eek-section.h"
@ -36,12 +36,7 @@ enum {
PROP_LAST PROP_LAST
}; };
G_DEFINE_TYPE (EekRenderer, eek_renderer, G_TYPE_OBJECT); typedef struct _EekRendererPrivate
#define EEK_RENDERER_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_RENDERER, EekRendererPrivate))
struct _EekRendererPrivate
{ {
EekKeyboard *keyboard; EekKeyboard *keyboard;
PangoContext *pcontext; PangoContext *pcontext;
@ -53,16 +48,22 @@ struct _EekRendererPrivate
gdouble allocation_width; gdouble allocation_width;
gdouble allocation_height; gdouble allocation_height;
gdouble scale; gdouble scale;
gint scale_factor; /* the outputs scale factor */
gint origin_x;
gint origin_y;
PangoFontDescription *ascii_font; PangoFontDescription *ascii_font;
PangoFontDescription *font; PangoFontDescription *font;
GHashTable *outline_surface_cache; GHashTable *outline_surface_cache;
GHashTable *active_outline_surface_cache; GHashTable *active_outline_surface_cache;
GHashTable *icons;
cairo_surface_t *keyboard_surface; cairo_surface_t *keyboard_surface;
gulong symbol_index_changed_handler; gulong symbol_index_changed_handler;
EekTheme *theme; EekTheme *theme;
}; } EekRendererPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (EekRenderer, eek_renderer, G_TYPE_OBJECT)
static const EekColor DEFAULT_FOREGROUND_COLOR = {0.3, 0.3, 0.3, 1.0}; static const EekColor DEFAULT_FOREGROUND_COLOR = {0.3, 0.3, 0.3, 1.0};
static const EekColor DEFAULT_BACKGROUND_COLOR = {1.0, 1.0, 1.0, 1.0}; static const EekColor DEFAULT_BACKGROUND_COLOR = {1.0, 1.0, 1.0, 1.0};
@ -106,18 +107,17 @@ create_keyboard_surface_key_callback (EekElement *element,
gpointer user_data) gpointer user_data)
{ {
CreateKeyboardSurfaceCallbackData *data = user_data; CreateKeyboardSurfaceCallbackData *data = user_data;
EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(data->renderer);
EekBounds bounds; EekBounds bounds;
cairo_save (data->cr); cairo_save (data->cr);
eek_element_get_bounds (element, &bounds); eek_element_get_bounds (element, &bounds);
cairo_translate (data->cr, bounds.x * priv->scale, bounds.y * priv->scale); cairo_translate (data->cr, bounds.x, bounds.y);
cairo_rectangle (data->cr, cairo_rectangle (data->cr,
0.0, 0.0,
0.0, 0.0,
bounds.width * priv->scale + 100, bounds.width + 100,
bounds.height * priv->scale + 100); bounds.height + 100);
cairo_clip (data->cr); cairo_clip (data->cr);
render_key (data->renderer, data->cr, EEK_KEY(element), FALSE); render_key (data->renderer, data->cr, EEK_KEY(element), FALSE);
@ -129,18 +129,17 @@ create_keyboard_surface_section_callback (EekElement *element,
gpointer user_data) gpointer user_data)
{ {
CreateKeyboardSurfaceCallbackData *data = user_data; CreateKeyboardSurfaceCallbackData *data = user_data;
EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(data->renderer);
EekBounds bounds; EekBounds bounds;
gint angle; gint angle;
cairo_save (data->cr); cairo_save (data->cr);
eek_element_get_bounds (element, &bounds); eek_element_get_bounds (element, &bounds);
cairo_translate (data->cr, bounds.x * priv->scale, bounds.y * priv->scale); cairo_translate (data->cr, bounds.x, bounds.y);
angle = eek_section_get_angle (EEK_SECTION(element)); angle = eek_section_get_angle (EEK_SECTION(element));
cairo_rotate (data->cr, angle * G_PI / 180); cairo_rotate (data->cr, angle * G_PI / 180);
eek_container_foreach_child (EEK_CONTAINER(element), eek_container_foreach_child (EEK_CONTAINER(element),
create_keyboard_surface_key_callback, create_keyboard_surface_key_callback,
data); data);
@ -148,12 +147,11 @@ create_keyboard_surface_section_callback (EekElement *element,
cairo_restore (data->cr); cairo_restore (data->cr);
} }
static cairo_surface_t * void
create_keyboard_surface (EekRenderer *renderer) render_keyboard_surface (EekRenderer *renderer)
{ {
EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(renderer); EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
EekBounds bounds; EekBounds bounds;
cairo_surface_t *keyboard_surface;
CreateKeyboardSurfaceCallbackData data; CreateKeyboardSurfaceCallbackData data;
EekColor foreground, background; EekColor foreground, background;
@ -165,13 +163,13 @@ create_keyboard_surface (EekRenderer *renderer)
&background); &background);
eek_element_get_bounds (EEK_ELEMENT(priv->keyboard), &bounds); eek_element_get_bounds (EEK_ELEMENT(priv->keyboard), &bounds);
keyboard_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
ceil(bounds.width * priv->scale), data.cr = cairo_create (priv->keyboard_surface);
ceil(bounds.height * priv->scale));
data.cr = cairo_create (keyboard_surface);
data.renderer = renderer; data.renderer = renderer;
cairo_translate (data.cr, bounds.x * priv->scale, bounds.y * priv->scale); cairo_save (data.cr);
cairo_scale (data.cr, priv->scale, priv->scale);
cairo_translate (data.cr, bounds.x, bounds.y);
/* blank background */ /* blank background */
cairo_set_source_rgba (data.cr, cairo_set_source_rgba (data.cr,
@ -191,9 +189,9 @@ create_keyboard_surface (EekRenderer *renderer)
eek_container_foreach_child (EEK_CONTAINER(priv->keyboard), eek_container_foreach_child (EEK_CONTAINER(priv->keyboard),
create_keyboard_surface_section_callback, create_keyboard_surface_section_callback,
&data); &data);
cairo_destroy (data.cr); cairo_restore (data.cr);
return keyboard_surface; cairo_destroy (data.cr);
} }
static void static void
@ -202,7 +200,7 @@ render_key_outline (EekRenderer *renderer,
EekKey *key, EekKey *key,
gboolean active) gboolean active)
{ {
EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(renderer); EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
EekOutline *outline; EekOutline *outline;
EekBounds bounds; EekBounds bounds;
guint oref; guint oref;
@ -216,7 +214,7 @@ render_key_outline (EekRenderer *renderer,
outline = eek_keyboard_get_outline (priv->keyboard, oref); outline = eek_keyboard_get_outline (priv->keyboard, oref);
if (outline == NULL) if (outline == NULL)
return; return;
theme_node = g_object_get_data (G_OBJECT(key), theme_node = g_object_get_data (G_OBJECT(key),
active ? active ?
"theme-node-pressed" : "theme-node-pressed" :
@ -246,15 +244,10 @@ render_key_outline (EekRenderer *renderer,
border_color.alpha = foreground.alpha; border_color.alpha = foreground.alpha;
} }
eek_element_get_bounds(EEK_ELEMENT(key), &bounds);
outline = eek_outline_copy (outline); outline = eek_outline_copy (outline);
for (guint i = 0; i < outline->num_points; i++) {
outline->points[i].x *= priv->scale;
outline->points[i].y *= priv->scale;
}
cairo_translate (cr, cairo_translate (cr, border_width, border_width);
border_width * priv->scale,
border_width * priv->scale);
if (gradient_type != EEK_GRADIENT_NONE) { if (gradient_type != EEK_GRADIENT_NONE) {
cairo_pattern_t *pat; cairo_pattern_t *pat;
@ -265,17 +258,17 @@ render_key_outline (EekRenderer *renderer,
pat = cairo_pattern_create_linear (0.0, pat = cairo_pattern_create_linear (0.0,
0.0, 0.0,
0.0, 0.0,
bounds.height * priv->scale); bounds.height);
break; break;
case EEK_GRADIENT_HORIZONTAL: case EEK_GRADIENT_HORIZONTAL:
pat = cairo_pattern_create_linear (0.0, pat = cairo_pattern_create_linear (0.0,
0.0, 0.0,
bounds.width * priv->scale, bounds.width,
0.0); 0.0);
break; break;
case EEK_GRADIENT_RADIAL: case EEK_GRADIENT_RADIAL:
cx = bounds.width / 2 * priv->scale; cx = bounds.width / 2;
cy = bounds.height / 2 * priv->scale; cy = bounds.height / 2;
pat = cairo_pattern_create_radial (cx, pat = cairo_pattern_create_radial (cx,
cy, cy,
0, 0,
@ -332,105 +325,18 @@ render_key_outline (EekRenderer *renderer,
outline->num_points); outline->num_points);
cairo_stroke (cr); cairo_stroke (cr);
cairo_translate (cr, cairo_translate (cr, -border_width, -border_width);
-border_width * priv->scale,
-border_width * priv->scale);
eek_outline_free (outline); eek_outline_free (outline);
} }
struct _CalculateFontSizeCallbackData {
gdouble size;
gboolean ascii;
EekRenderer *renderer;
const PangoFontDescription *base_font;
};
typedef struct _CalculateFontSizeCallbackData CalculateFontSizeCallbackData;
static void
calculate_font_size_key_callback (EekElement *element, gpointer user_data)
{
CalculateFontSizeCallbackData *data = user_data;
EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(data->renderer);
gdouble sx, sy;
PangoFontDescription *font;
PangoRectangle extents = { 0, };
PangoLayout *layout;
gdouble size;
EekBounds bounds;
const gchar *label = NULL;
if (data->ascii)
label = "M";
else {
EekSymbol *symbol;
symbol = eek_key_get_symbol (EEK_KEY(element));
if (symbol &&
eek_symbol_get_category (symbol) == EEK_SYMBOL_CATEGORY_LETTER)
label = eek_symbol_get_label (symbol);
if (!label)
label = "M";
}
font = pango_font_description_copy (data->base_font);
eek_element_get_bounds (element, &bounds);
size = eek_bounds_long_side (&bounds) * PANGO_SCALE;
pango_font_description_set_size (font, size);
layout = pango_layout_new (priv->pcontext);
pango_layout_set_font_description (layout, font);
pango_font_description_free (font);
pango_layout_set_text (layout, label, -1);
pango_layout_get_extents (layout, NULL, &extents);
g_object_unref (layout);
sx = sy = 1.0;
if (extents.width > bounds.width * PANGO_SCALE)
sx = bounds.width * PANGO_SCALE / extents.width;
if (extents.height > bounds.height * PANGO_SCALE)
sy = bounds.height * PANGO_SCALE / extents.height;
size *= MIN(sx, sy);
if (size < data->size)
data->size = size;
}
static void
calculate_font_size_section_callback (EekElement *element, gpointer user_data)
{
eek_container_foreach_child (EEK_CONTAINER(element),
calculate_font_size_key_callback,
user_data);
}
static gdouble
calculate_font_size (EekRenderer *renderer,
const PangoFontDescription *base_font,
gboolean ascii)
{
EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(renderer);
CalculateFontSizeCallbackData data;
data.size = G_MAXDOUBLE;
data.ascii = ascii;
data.renderer = renderer;
data.base_font = base_font;
eek_container_foreach_child (EEK_CONTAINER(priv->keyboard),
calculate_font_size_section_callback,
&data);
return data.size;
}
static void static void
render_key (EekRenderer *self, render_key (EekRenderer *self,
cairo_t *cr, cairo_t *cr,
EekKey *key, EekKey *key,
gboolean active) gboolean active)
{ {
EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(self); EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
EekOutline *outline; EekOutline *outline;
cairo_surface_t *outline_surface; cairo_surface_t *outline_surface;
EekBounds bounds; EekBounds bounds;
@ -441,6 +347,9 @@ render_key (EekRenderer *self,
PangoRectangle extents = { 0, }; PangoRectangle extents = { 0, };
EekColor foreground; EekColor foreground;
if (!eek_key_has_label(key))
return;
oref = eek_key_get_oref (key); oref = eek_key_get_oref (key);
outline = eek_keyboard_get_outline (priv->keyboard, oref); outline = eek_keyboard_get_outline (priv->keyboard, oref);
if (outline == NULL) if (outline == NULL)
@ -448,8 +357,6 @@ render_key (EekRenderer *self,
/* render outline */ /* render outline */
eek_element_get_bounds (EEK_ELEMENT(key), &bounds); eek_element_get_bounds (EEK_ELEMENT(key), &bounds);
bounds.width *= priv->scale;
bounds.height *= priv->scale;
if (active) if (active)
outline_surface_cache = priv->active_outline_surface_cache; outline_surface_cache = priv->active_outline_surface_cache;
@ -460,7 +367,8 @@ render_key (EekRenderer *self,
if (!outline_surface) { if (!outline_surface) {
cairo_t *cr; cairo_t *cr;
// Outline will be drawn on the outside of the button, so the surface needs to be bigger than the button // Outline will be drawn on the outside of the button, so the
// surface needs to be bigger than the button
outline_surface = outline_surface =
cairo_image_surface_create (CAIRO_FORMAT_ARGB32, cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
(int)ceil(bounds.width) + 10, (int)ceil(bounds.width) + 10,
@ -486,44 +394,37 @@ render_key (EekRenderer *self,
cairo_set_source_surface (cr, outline_surface, 0.0, 0.0); cairo_set_source_surface (cr, outline_surface, 0.0, 0.0);
cairo_paint (cr); cairo_paint (cr);
eek_renderer_get_foreground_color (self, EEK_ELEMENT(key), &foreground);
/* render icon (if any) */ /* render icon (if any) */
symbol = eek_key_get_symbol_with_fallback (key, 0, 0); symbol = eek_key_get_symbol_with_fallback (key, 0, 0);
if (!symbol) if (!symbol)
return; return;
if (eek_symbol_get_icon_name (symbol)) { if (eek_symbol_get_icon_name (symbol)) {
gint scale = priv->scale_factor;
cairo_surface_t *icon_surface = cairo_surface_t *icon_surface =
eek_renderer_get_icon_surface (self, eek_renderer_get_icon_surface (self,
eek_symbol_get_icon_name (symbol), eek_symbol_get_icon_name (symbol),
MIN(bounds.width, bounds.height) * 0.7); 16,
scale);
if (icon_surface) { if (icon_surface) {
gint width = cairo_image_surface_get_width (icon_surface); gint width = cairo_image_surface_get_width (icon_surface);
gint height = cairo_image_surface_get_height (icon_surface); gint height = cairo_image_surface_get_height (icon_surface);
gdouble scale;
if (width < bounds.width && height < bounds.height)
scale = 1;
else {
if (height * bounds.width / width <= bounds.height)
scale = bounds.width / width;
else if (width * bounds.height / height <= bounds.width)
scale = bounds.height / height;
else {
if (width * bounds.height < height * bounds.width)
scale = width / bounds.width;
else
scale = height / bounds.height;
}
}
cairo_save (cr); cairo_save (cr);
cairo_translate (cr, cairo_translate (cr,
(bounds.width - width * scale) / 2, (bounds.width - width / scale) / 2,
(bounds.height - height * scale) / 2); (bounds.height - height / scale) / 2);
cairo_rectangle (cr, 0, 0, width, height); cairo_rectangle (cr, 0, 0, width, height);
cairo_clip (cr); cairo_clip (cr);
cairo_set_source_surface (cr, icon_surface, 0.0, 0.0); /* Draw the shape of the icon using the foreground color */
cairo_paint (cr); cairo_set_source_rgba (cr, foreground.red,
foreground.green,
foreground.blue,
foreground.alpha);
cairo_mask_surface (cr, icon_surface, 0.0, 0.0);
cairo_fill (cr);
cairo_restore (cr); cairo_restore (cr);
return; return;
} }
@ -540,7 +441,6 @@ render_key (EekRenderer *self,
(bounds.width - extents.width / PANGO_SCALE) / 2, (bounds.width - extents.width / PANGO_SCALE) / 2,
(bounds.height - extents.height / PANGO_SCALE) / 2); (bounds.height - extents.height / PANGO_SCALE) / 2);
eek_renderer_get_foreground_color (self, EEK_ELEMENT(key), &foreground);
cairo_set_source_rgba (cr, cairo_set_source_rgba (cr,
foreground.red, foreground.red,
foreground.green, foreground.green,
@ -589,9 +489,8 @@ get_text_property_for_category (EekSymbolCategory category)
{ EEK_SYMBOL_CATEGORY_FUNCTION, TRUE, 0.5, FALSE }, { EEK_SYMBOL_CATEGORY_FUNCTION, TRUE, 0.5, FALSE },
{ EEK_SYMBOL_CATEGORY_KEYNAME, TRUE, 0.5, TRUE } { EEK_SYMBOL_CATEGORY_KEYNAME, TRUE, 0.5, TRUE }
}; };
gint i;
for (i = 0; i < G_N_ELEMENTS(props); i++) for (uint i = 0; i < G_N_ELEMENTS(props); i++)
if (props[i].category == category) if (props[i].category == category)
return &props[i]; return &props[i];
@ -603,7 +502,7 @@ eek_renderer_real_render_key_label (EekRenderer *self,
PangoLayout *layout, PangoLayout *layout,
EekKey *key) EekKey *key)
{ {
EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(self); EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
EekSymbol *symbol; EekSymbol *symbol;
EekSymbolCategory category; EekSymbolCategory category;
const gchar *label; const gchar *label;
@ -631,13 +530,16 @@ eek_renderer_real_render_key_label (EekRenderer *self,
base_font = eek_theme_node_get_font (theme_node); base_font = eek_theme_node_get_font (theme_node);
else else
base_font = pango_context_get_font_description (priv->pcontext); base_font = pango_context_get_font_description (priv->pcontext);
ascii_size = calculate_font_size (self, base_font, TRUE); // FIXME: Base font size on the same size unit used for button sizing,
// and make the default about 1/3 of the current row height
ascii_size = 30000.0;
priv->ascii_font = pango_font_description_copy (base_font); priv->ascii_font = pango_font_description_copy (base_font);
pango_font_description_set_size (priv->ascii_font, ascii_size); pango_font_description_set_size (priv->ascii_font,
(gint)round(ascii_size));
size = calculate_font_size (self, base_font, FALSE); size = 30000.0;
priv->font = pango_font_description_copy (base_font); priv->font = pango_font_description_copy (base_font);
pango_font_description_set_size (priv->font, size * 0.6); pango_font_description_set_size (priv->font, (gint)round(size * 0.6));
} }
eek_element_get_bounds (EEK_ELEMENT(key), &bounds); eek_element_get_bounds (EEK_ELEMENT(key), &bounds);
@ -651,8 +553,8 @@ eek_renderer_real_render_key_label (EekRenderer *self,
priv->ascii_font : priv->ascii_font :
priv->font); priv->font);
pango_font_description_set_size (font, pango_font_description_set_size (font,
pango_font_description_get_size (font) * (gint)round(pango_font_description_get_size (font) *
prop->scale * priv->scale * scale); prop->scale * scale));
pango_layout_set_font_description (layout, font); pango_layout_set_font_description (layout, font);
pango_font_description_free (font); pango_font_description_free (font);
@ -661,7 +563,7 @@ eek_renderer_real_render_key_label (EekRenderer *self,
if (line->resolved_dir == PANGO_DIRECTION_RTL) if (line->resolved_dir == PANGO_DIRECTION_RTL)
pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT); pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT);
pango_layout_set_width (layout, pango_layout_set_width (layout,
PANGO_SCALE * bounds.width * priv->scale * scale); PANGO_SCALE * bounds.width * scale);
if (prop->ellipses) if (prop->ellipses)
pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END); pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
} }
@ -686,7 +588,10 @@ eek_renderer_real_render_key (EekRenderer *self,
gdouble scale, gdouble scale,
gboolean rotate) gboolean rotate)
{ {
EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
cairo_save (cr); cairo_save (cr);
cairo_translate (cr, priv->origin_x, priv->origin_y);
eek_renderer_apply_transformation_for_key (self, cr, key, scale, rotate); eek_renderer_apply_transformation_for_key (self, cr, key, scale, rotate);
render_key (self, cr, key, eek_key_is_pressed (key) || eek_key_is_locked (key)); render_key (self, cr, key, eek_key_is_pressed (key) || eek_key_is_locked (key));
cairo_restore (cr); cairo_restore (cr);
@ -696,20 +601,32 @@ static void
eek_renderer_real_render_keyboard (EekRenderer *self, eek_renderer_real_render_keyboard (EekRenderer *self,
cairo_t *cr) cairo_t *cr)
{ {
EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(self); EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
cairo_pattern_t *source; cairo_pattern_t *source;
g_return_if_fail (priv->keyboard); g_return_if_fail (priv->keyboard);
g_return_if_fail (priv->allocation_width > 0.0); g_return_if_fail (priv->allocation_width > 0.0);
g_return_if_fail (priv->allocation_height > 0.0); g_return_if_fail (priv->allocation_height > 0.0);
if (!priv->keyboard_surface) cairo_save (cr);
priv->keyboard_surface = create_keyboard_surface (self);
cairo_translate (cr, priv->origin_x, priv->origin_y);
if (priv->keyboard_surface)
cairo_surface_destroy (priv->keyboard_surface);
priv->keyboard_surface = cairo_surface_create_for_rectangle (
cairo_get_target (cr), 0, 0,
priv->allocation_width, priv->allocation_height);
render_keyboard_surface (self);
cairo_set_source_surface (cr, priv->keyboard_surface, 0.0, 0.0); cairo_set_source_surface (cr, priv->keyboard_surface, 0.0, 0.0);
source = cairo_get_source (cr); source = cairo_get_source (cr);
cairo_pattern_set_extend (source, CAIRO_EXTEND_PAD); cairo_pattern_set_extend (source, CAIRO_EXTEND_PAD);
cairo_paint (cr); cairo_paint (cr);
cairo_restore (cr);
} }
static void static void
@ -718,7 +635,8 @@ eek_renderer_set_property (GObject *object,
const GValue *value, const GValue *value,
GParamSpec *pspec) GParamSpec *pspec)
{ {
EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(object); EekRendererPrivate *priv = eek_renderer_get_instance_private (
EEK_RENDERER(object));
switch (prop_id) { switch (prop_id) {
case PROP_KEYBOARD: case PROP_KEYBOARD:
@ -746,7 +664,8 @@ eek_renderer_get_property (GObject *object,
GValue *value, GValue *value,
GParamSpec *pspec) GParamSpec *pspec)
{ {
EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(object); EekRendererPrivate *priv = eek_renderer_get_instance_private (
EEK_RENDERER(object));
switch (prop_id) { switch (prop_id) {
case PROP_KEYBOARD: case PROP_KEYBOARD:
@ -761,7 +680,8 @@ eek_renderer_get_property (GObject *object,
static void static void
eek_renderer_dispose (GObject *object) eek_renderer_dispose (GObject *object)
{ {
EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(object); EekRenderer *self = EEK_RENDERER (object);
EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
if (priv->keyboard) { if (priv->keyboard) {
if (g_signal_handler_is_connected (priv->keyboard, if (g_signal_handler_is_connected (priv->keyboard,
@ -776,6 +696,8 @@ eek_renderer_dispose (GObject *object)
priv->pcontext = NULL; priv->pcontext = NULL;
} }
g_clear_pointer (&priv->icons, g_hash_table_destroy);
/* this will release all allocated surfaces and font if any */ /* this will release all allocated surfaces and font if any */
invalidate (EEK_RENDERER(object)); invalidate (EEK_RENDERER(object));
@ -785,7 +707,9 @@ eek_renderer_dispose (GObject *object)
static void static void
eek_renderer_finalize (GObject *object) eek_renderer_finalize (GObject *object)
{ {
EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(object); EekRenderer *self = EEK_RENDERER(object);
EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
g_hash_table_destroy (priv->outline_surface_cache); g_hash_table_destroy (priv->outline_surface_cache);
g_hash_table_destroy (priv->active_outline_surface_cache); g_hash_table_destroy (priv->active_outline_surface_cache);
pango_font_description_free (priv->ascii_font); pango_font_description_free (priv->ascii_font);
@ -799,9 +723,6 @@ eek_renderer_class_init (EekRendererClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec; GParamSpec *pspec;
g_type_class_add_private (gobject_class,
sizeof (EekRendererPrivate));
klass->render_key_label = eek_renderer_real_render_key_label; klass->render_key_label = eek_renderer_real_render_key_label;
klass->render_key_outline = eek_renderer_real_render_key_outline; klass->render_key_outline = eek_renderer_real_render_key_outline;
klass->render_key = eek_renderer_real_render_key; klass->render_key = eek_renderer_real_render_key;
@ -834,9 +755,8 @@ eek_renderer_class_init (EekRendererClass *klass)
static void static void
eek_renderer_init (EekRenderer *self) eek_renderer_init (EekRenderer *self)
{ {
EekRendererPrivate *priv; EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
priv = self->priv = EEK_RENDERER_GET_PRIVATE(self);
priv->keyboard = NULL; priv->keyboard = NULL;
priv->pcontext = NULL; priv->pcontext = NULL;
priv->default_foreground_color = DEFAULT_FOREGROUND_COLOR; priv->default_foreground_color = DEFAULT_FOREGROUND_COLOR;
@ -845,6 +765,7 @@ eek_renderer_init (EekRenderer *self)
priv->allocation_width = 0.0; priv->allocation_width = 0.0;
priv->allocation_height = 0.0; priv->allocation_height = 0.0;
priv->scale = 1.0; priv->scale = 1.0;
priv->scale_factor = 1;
priv->font = NULL; priv->font = NULL;
priv->outline_surface_cache = priv->outline_surface_cache =
g_hash_table_new_full (g_direct_hash, g_hash_table_new_full (g_direct_hash,
@ -858,20 +779,30 @@ eek_renderer_init (EekRenderer *self)
(GDestroyNotify)cairo_surface_destroy); (GDestroyNotify)cairo_surface_destroy);
priv->keyboard_surface = NULL; priv->keyboard_surface = NULL;
priv->symbol_index_changed_handler = 0; priv->symbol_index_changed_handler = 0;
GtkIconTheme *theme = gtk_icon_theme_get_default ();
gtk_icon_theme_add_resource_path (theme, "/sm/puri/squeekboard/icons");
priv->icons = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
(GDestroyNotify)cairo_surface_destroy);
} }
static void static void
invalidate (EekRenderer *renderer) invalidate (EekRenderer *renderer)
{ {
if (renderer->priv->outline_surface_cache) EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
g_hash_table_remove_all (renderer->priv->outline_surface_cache);
if (renderer->priv->active_outline_surface_cache) if (priv->outline_surface_cache)
g_hash_table_remove_all (renderer->priv->active_outline_surface_cache); g_hash_table_remove_all (priv->outline_surface_cache);
if (renderer->priv->keyboard_surface) { if (priv->active_outline_surface_cache)
cairo_surface_destroy (renderer->priv->keyboard_surface); g_hash_table_remove_all (priv->active_outline_surface_cache);
renderer->priv->keyboard_surface = NULL;
if (priv->keyboard_surface) {
cairo_surface_destroy (priv->keyboard_surface);
priv->keyboard_surface = NULL;
} }
} }
@ -906,24 +837,24 @@ eek_renderer_set_allocation_size (EekRenderer *renderer,
g_return_if_fail (EEK_IS_RENDERER(renderer)); g_return_if_fail (EEK_IS_RENDERER(renderer));
g_return_if_fail (width > 0.0 && height > 0.0); g_return_if_fail (width > 0.0 && height > 0.0);
renderer->priv->allocation_width = width; EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
renderer->priv->allocation_height = height;
eek_element_get_bounds (EEK_ELEMENT(renderer->priv->keyboard), &bounds); priv->allocation_width = width;
priv->allocation_height = height;
if (bounds.height * width / bounds.width <= height) /* Calculate a scale factor to use when rendering the keyboard into the
scale = width / bounds.width; available space. */
else if (bounds.width * height / bounds.height <= width) eek_element_get_bounds (EEK_ELEMENT(priv->keyboard), &bounds);
scale = height / bounds.height;
else {
if (bounds.width * height < bounds.height * width)
scale = bounds.width / width;
else
scale = bounds.height / height;
}
if (scale != renderer->priv->scale) { gdouble w = (bounds.x * 2) + bounds.width;
renderer->priv->scale = scale; gdouble h = (bounds.y * 2) + bounds.height;
scale = MIN(width / w, height / h);
if (scale != priv->scale) {
priv->scale = scale;
priv->origin_x = 0;
priv->origin_y = 0;
invalidate (renderer); invalidate (renderer);
} }
} }
@ -937,11 +868,13 @@ eek_renderer_get_size (EekRenderer *renderer,
g_return_if_fail (EEK_IS_RENDERER(renderer)); g_return_if_fail (EEK_IS_RENDERER(renderer));
eek_element_get_bounds (EEK_ELEMENT(renderer->priv->keyboard), &bounds); EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
eek_element_get_bounds (EEK_ELEMENT(priv->keyboard), &bounds);
if (width) if (width)
*width = bounds.width * renderer->priv->scale; *width = bounds.width;
if (height) if (height)
*height = bounds.height * renderer->priv->scale; *height = bounds.height;
} }
void void
@ -954,26 +887,23 @@ eek_renderer_get_key_bounds (EekRenderer *renderer,
EekBounds section_bounds, keyboard_bounds; EekBounds section_bounds, keyboard_bounds;
gint angle = 0; gint angle = 0;
EekPoint points[4], min, max; EekPoint points[4], min, max;
gint i;
g_return_if_fail (EEK_IS_RENDERER(renderer)); g_return_if_fail (EEK_IS_RENDERER(renderer));
g_return_if_fail (EEK_IS_KEY(key)); g_return_if_fail (EEK_IS_KEY(key));
g_return_if_fail (bounds != NULL); g_return_if_fail (bounds != NULL);
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
section = eek_element_get_parent (EEK_ELEMENT(key)); section = eek_element_get_parent (EEK_ELEMENT(key));
eek_element_get_bounds (EEK_ELEMENT(key), bounds); eek_element_get_bounds (EEK_ELEMENT(key), bounds);
eek_element_get_bounds (section, &section_bounds); eek_element_get_bounds (section, &section_bounds);
eek_element_get_bounds (EEK_ELEMENT(renderer->priv->keyboard), eek_element_get_bounds (EEK_ELEMENT(priv->keyboard),
&keyboard_bounds); &keyboard_bounds);
if (!rotate) { if (!rotate) {
bounds->x += keyboard_bounds.x + section_bounds.x; bounds->x += keyboard_bounds.x + section_bounds.x;
bounds->y += keyboard_bounds.y + section_bounds.y; bounds->y += keyboard_bounds.y + section_bounds.y;
bounds->x *= renderer->priv->scale;
bounds->y *= renderer->priv->scale;
bounds->width *= renderer->priv->scale;
bounds->height *= renderer->priv->scale;
return; return;
} }
points[0].x = bounds->x; points[0].x = bounds->x;
@ -990,7 +920,7 @@ eek_renderer_get_key_bounds (EekRenderer *renderer,
min = points[2]; min = points[2];
max = points[0]; max = points[0];
for (i = 0; i < G_N_ELEMENTS(points); i++) { for (uint i = 0; i < G_N_ELEMENTS(points); i++) {
eek_point_rotate (&points[i], angle); eek_point_rotate (&points[i], angle);
if (points[i].x < min.x) if (points[i].x < min.x)
min.x = points[i].x; min.x = points[i].x;
@ -1005,24 +935,35 @@ eek_renderer_get_key_bounds (EekRenderer *renderer,
bounds->y = keyboard_bounds.y + section_bounds.y + min.y; bounds->y = keyboard_bounds.y + section_bounds.y + min.y;
bounds->width = (max.x - min.x); bounds->width = (max.x - min.x);
bounds->height = (max.y - min.y); bounds->height = (max.y - min.y);
bounds->x *= renderer->priv->scale;
bounds->y *= renderer->priv->scale;
bounds->width *= renderer->priv->scale;
bounds->height *= renderer->priv->scale;
} }
gdouble gdouble
eek_renderer_get_scale (EekRenderer *renderer) eek_renderer_get_scale (EekRenderer *renderer)
{ {
g_return_val_if_fail (EEK_IS_RENDERER(renderer), 0); g_return_val_if_fail (EEK_IS_RENDERER(renderer), 0);
return renderer->priv->scale;
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
return priv->scale;
}
void
eek_renderer_set_scale_factor (EekRenderer *renderer, gint scale)
{
g_return_if_fail (EEK_IS_RENDERER(renderer));
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
priv->scale_factor = scale;
} }
PangoLayout * PangoLayout *
eek_renderer_create_pango_layout (EekRenderer *renderer) eek_renderer_create_pango_layout (EekRenderer *renderer)
{ {
g_return_val_if_fail (EEK_IS_RENDERER(renderer), NULL); g_return_val_if_fail (EEK_IS_RENDERER(renderer), NULL);
return pango_layout_new (renderer->priv->pcontext);
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
return pango_layout_new (priv->pcontext);
} }
void void
@ -1058,16 +999,35 @@ eek_renderer_render_key_outline (EekRenderer *renderer,
cairo_surface_t * cairo_surface_t *
eek_renderer_get_icon_surface (EekRenderer *renderer, eek_renderer_get_icon_surface (EekRenderer *renderer,
const gchar *icon_name, const gchar *icon_name,
gint size) gint size,
gint scale)
{ {
EekRendererClass *klass; GError *error = NULL;
cairo_surface_t *surface;
g_return_val_if_fail (EEK_IS_RENDERER(renderer), NULL); g_return_val_if_fail (EEK_IS_RENDERER(renderer), NULL);
klass = EEK_RENDERER_GET_CLASS(renderer); EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
if (klass->get_icon_surface)
return klass->get_icon_surface (renderer, icon_name, size); surface = g_hash_table_lookup (priv->icons, icon_name);
return NULL; if (!surface) {
surface = gtk_icon_theme_load_surface (gtk_icon_theme_get_default (),
icon_name,
size,
scale,
NULL,
0,
&error);
g_hash_table_insert (priv->icons, g_strdup(icon_name), surface);
if (surface == NULL) {
g_warning ("can't get icon surface for %s: %s",
icon_name,
error->message);
g_error_free (error);
return NULL;
}
}
return surface;
} }
void void
@ -1100,7 +1060,9 @@ eek_renderer_set_default_foreground_color (EekRenderer *renderer,
g_return_if_fail (EEK_IS_RENDERER(renderer)); g_return_if_fail (EEK_IS_RENDERER(renderer));
g_return_if_fail (color); g_return_if_fail (color);
memcpy (&renderer->priv->default_foreground_color, color, sizeof(EekColor)); EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
memcpy (&priv->default_foreground_color, color, sizeof(EekColor));
} }
void void
@ -1110,7 +1072,9 @@ eek_renderer_set_default_background_color (EekRenderer *renderer,
g_return_if_fail (EEK_IS_RENDERER(renderer)); g_return_if_fail (EEK_IS_RENDERER(renderer));
g_return_if_fail (color); g_return_if_fail (color);
memcpy (&renderer->priv->default_background_color, color, sizeof(EekColor)); EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
memcpy (&priv->default_background_color, color, sizeof(EekColor));
} }
void void
@ -1123,11 +1087,13 @@ eek_renderer_get_foreground_color (EekRenderer *renderer,
g_return_if_fail (EEK_IS_RENDERER(renderer)); g_return_if_fail (EEK_IS_RENDERER(renderer));
g_return_if_fail (color); g_return_if_fail (color);
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
theme_node = g_object_get_data (G_OBJECT(element), "theme-node"); theme_node = g_object_get_data (G_OBJECT(element), "theme-node");
if (theme_node) if (theme_node)
eek_theme_node_get_foreground_color (theme_node, color); eek_theme_node_get_foreground_color (theme_node, color);
else else
memcpy (color, &renderer->priv->default_foreground_color, memcpy (color, &priv->default_foreground_color,
sizeof(EekColor)); sizeof(EekColor));
} }
@ -1141,11 +1107,13 @@ eek_renderer_get_background_color (EekRenderer *renderer,
g_return_if_fail (EEK_IS_RENDERER(renderer)); g_return_if_fail (EEK_IS_RENDERER(renderer));
g_return_if_fail (color); g_return_if_fail (color);
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
theme_node = g_object_get_data (G_OBJECT(element), "theme-node"); theme_node = g_object_get_data (G_OBJECT(element), "theme-node");
if (theme_node) if (theme_node)
eek_theme_node_get_background_color (theme_node, color); eek_theme_node_get_background_color (theme_node, color);
else else
memcpy (color, &renderer->priv->default_background_color, memcpy (color, &priv->default_background_color,
sizeof(EekColor)); sizeof(EekColor));
} }
@ -1194,7 +1162,6 @@ find_key_by_position_key_callback (EekElement *element,
FindKeyByPositionCallbackData *data = user_data; FindKeyByPositionCallbackData *data = user_data;
EekBounds bounds; EekBounds bounds;
EekPoint points[4]; EekPoint points[4];
gint i;
gboolean b1, b2, b3; gboolean b1, b2, b3;
eek_element_get_bounds (element, &bounds); eek_element_get_bounds (element, &bounds);
@ -1208,12 +1175,10 @@ find_key_by_position_key_callback (EekElement *element,
points[3].x = points[0].x; points[3].x = points[0].x;
points[3].y = points[2].y; points[3].y = points[2].y;
for (i = 0; i < G_N_ELEMENTS(points); i++) { for (uint i = 0; i < G_N_ELEMENTS(points); i++) {
eek_point_rotate (&points[i], data->angle); eek_point_rotate (&points[i], data->angle);
points[i].x += data->origin.x; points[i].x += data->origin.x;
points[i].y += data->origin.y; points[i].y += data->origin.y;
points[i].x *= data->renderer->priv->scale;
points[i].y *= data->renderer->priv->scale;
} }
b1 = sign (&data->point, &points[0], &points[1]) < 0.0; b1 = sign (&data->point, &points[0], &points[1]) < 0.0;
@ -1268,12 +1233,18 @@ eek_renderer_find_key_by_position (EekRenderer *renderer,
g_return_val_if_fail (EEK_IS_RENDERER(renderer), NULL); g_return_val_if_fail (EEK_IS_RENDERER(renderer), NULL);
eek_element_get_bounds (EEK_ELEMENT(renderer->priv->keyboard), &bounds); EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
x /= priv->scale;
y /= priv->scale;
x -= priv->origin_x;
y -= priv->origin_y;
if (x < bounds.x * renderer->priv->scale || eek_element_get_bounds (EEK_ELEMENT(priv->keyboard), &bounds);
y < bounds.y * renderer->priv->scale ||
x > bounds.width * renderer->priv->scale || if (x < bounds.x ||
y > bounds.height * renderer->priv->scale) y < bounds.y ||
x > bounds.width ||
y > bounds.height)
return NULL; return NULL;
data.point.x = x; data.point.x = x;
@ -1283,7 +1254,7 @@ eek_renderer_find_key_by_position (EekRenderer *renderer,
data.key = NULL; data.key = NULL;
data.renderer = renderer; data.renderer = renderer;
eek_container_find (EEK_CONTAINER(renderer->priv->keyboard), eek_container_find (EEK_CONTAINER(priv->keyboard),
find_key_by_position_section_callback, find_key_by_position_section_callback,
&data); &data);
return data.key; return data.key;
@ -1303,9 +1274,11 @@ create_theme_node_key_callback (EekElement *element,
CreateThemeNodeData *data = user_data; CreateThemeNodeData *data = user_data;
EekThemeNode *theme_node; EekThemeNode *theme_node;
EekRendererPrivate *priv = eek_renderer_get_instance_private (data->renderer);
theme_node = eek_theme_node_new (data->context, theme_node = eek_theme_node_new (data->context,
data->parent, data->parent,
data->renderer->priv->theme, priv->theme,
EEK_TYPE_KEY, EEK_TYPE_KEY,
eek_element_get_name (element), eek_element_get_name (element),
"key", "key",
@ -1318,7 +1291,7 @@ create_theme_node_key_callback (EekElement *element,
theme_node = eek_theme_node_new (data->context, theme_node = eek_theme_node_new (data->context,
data->parent, data->parent,
data->renderer->priv->theme, priv->theme,
EEK_TYPE_KEY, EEK_TYPE_KEY,
eek_element_get_name (element), eek_element_get_name (element),
"key", "key",
@ -1337,9 +1310,11 @@ create_theme_node_section_callback (EekElement *element,
CreateThemeNodeData *data = user_data; CreateThemeNodeData *data = user_data;
EekThemeNode *theme_node, *parent; EekThemeNode *theme_node, *parent;
EekRendererPrivate *priv = eek_renderer_get_instance_private (data->renderer);
theme_node = eek_theme_node_new (data->context, theme_node = eek_theme_node_new (data->context,
data->parent, data->parent,
data->renderer->priv->theme, priv->theme,
EEK_TYPE_SECTION, EEK_TYPE_SECTION,
eek_element_get_name (element), eek_element_get_name (element),
"section", "section",
@ -1368,22 +1343,25 @@ eek_renderer_set_theme (EekRenderer *renderer,
g_return_if_fail (EEK_IS_RENDERER(renderer)); g_return_if_fail (EEK_IS_RENDERER(renderer));
g_return_if_fail (EEK_IS_THEME(theme)); g_return_if_fail (EEK_IS_THEME(theme));
g_return_if_fail (renderer->priv->keyboard);
if (renderer->priv->theme) EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
g_object_unref (renderer->priv->theme);
renderer->priv->theme = g_object_ref (theme); g_return_if_fail (priv->keyboard);
if (priv->theme)
g_object_unref (priv->theme);
priv->theme = g_object_ref (theme);
theme_context = eek_theme_context_new (); theme_context = eek_theme_context_new ();
theme_node = eek_theme_node_new (theme_context, theme_node = eek_theme_node_new (theme_context,
NULL, NULL,
renderer->priv->theme, priv->theme,
EEK_TYPE_KEYBOARD, EEK_TYPE_KEYBOARD,
"keyboard", "keyboard",
"keyboard", "keyboard",
NULL, NULL,
NULL); NULL);
g_object_set_data_full (G_OBJECT(renderer->priv->keyboard), g_object_set_data_full (G_OBJECT(priv->keyboard),
"theme-node", "theme-node",
theme_node, theme_node,
(GDestroyNotify)g_object_unref); (GDestroyNotify)g_object_unref);
@ -1391,7 +1369,7 @@ eek_renderer_set_theme (EekRenderer *renderer,
data.context = theme_context; data.context = theme_context;
data.parent = theme_node; data.parent = theme_node;
data.renderer = renderer; data.renderer = renderer;
eek_container_foreach_child (EEK_CONTAINER(renderer->priv->keyboard), eek_container_foreach_child (EEK_CONTAINER(priv->keyboard),
create_theme_node_section_callback, create_theme_node_section_callback,
&data); &data);
} }

View File

@ -31,21 +31,7 @@
G_BEGIN_DECLS G_BEGIN_DECLS
#define EEK_TYPE_RENDERER (eek_renderer_get_type()) #define EEK_TYPE_RENDERER (eek_renderer_get_type())
#define EEK_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEK_TYPE_RENDERER, EekRenderer)) G_DECLARE_DERIVABLE_TYPE (EekRenderer, eek_renderer, EEK, RENDERER, GObject)
#define EEK_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEK_TYPE_RENDERER, EekRendererClass))
#define EEK_IS_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEK_TYPE_RENDERER))
#define EEK_IS_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_RENDERER))
#define EEK_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_RENDERER, EekRendererClass))
typedef struct _EekRenderer EekRenderer;
typedef struct _EekRendererClass EekRendererClass;
typedef struct _EekRendererPrivate EekRendererPrivate;
struct _EekRenderer {
GObject parent;
EekRendererPrivate *priv;
};
struct _EekRendererClass struct _EekRendererClass
{ {
@ -72,7 +58,8 @@ struct _EekRendererClass
cairo_surface_t *(* get_icon_surface) (EekRenderer *self, cairo_surface_t *(* get_icon_surface) (EekRenderer *self,
const gchar *icon_name, const gchar *icon_name,
gint size); gint size,
gint scale);
/*< private >*/ /*< private >*/
/* padding */ /* padding */
@ -95,6 +82,8 @@ void eek_renderer_get_key_bounds (EekRenderer *renderer,
gboolean rotate); gboolean rotate);
gdouble eek_renderer_get_scale (EekRenderer *renderer); gdouble eek_renderer_get_scale (EekRenderer *renderer);
void eek_renderer_set_scale_factor (EekRenderer *renderer,
gint scale);
PangoLayout *eek_renderer_create_pango_layout PangoLayout *eek_renderer_create_pango_layout
(EekRenderer *renderer); (EekRenderer *renderer);
@ -117,7 +106,8 @@ void eek_renderer_render_key (EekRenderer *renderer,
cairo_surface_t *eek_renderer_get_icon_surface (EekRenderer *renderer, cairo_surface_t *eek_renderer_get_icon_surface (EekRenderer *renderer,
const gchar *icon_name, const gchar *icon_name,
gint size); gint size,
gint scale);
void eek_renderer_render_keyboard (EekRenderer *renderer, void eek_renderer_render_keyboard (EekRenderer *renderer,
cairo_t *cr); cairo_t *cr);

View File

@ -1,17 +1,17 @@
/* /*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org> * Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc. * Copyright (C) 2010-2011 Red Hat, Inc.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License * modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of * as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version. * the License, or (at your option) any later version.
* *
* This library is distributed in the hope that it will be useful, but * This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
@ -27,9 +27,7 @@
* of one or more keys of the #EekKeyClass class. * of one or more keys of the #EekKeyClass class.
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */
#include <string.h> #include <string.h>
@ -52,11 +50,6 @@ enum {
static guint signals[LAST_SIGNAL] = { 0, }; static guint signals[LAST_SIGNAL] = { 0, };
G_DEFINE_TYPE (EekSection, eek_section, EEK_TYPE_CONTAINER);
#define EEK_SECTION_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_SECTION, EekSectionPrivate))
struct _EekRow struct _EekRow
{ {
gint num_columns; gint num_columns;
@ -65,17 +58,19 @@ struct _EekRow
typedef struct _EekRow EekRow; typedef struct _EekRow EekRow;
struct _EekSectionPrivate typedef struct _EekSectionPrivate
{ {
gint angle; gint angle;
GSList *rows; GSList *rows;
EekModifierType modifiers; EekModifierType modifiers;
}; } EekSectionPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (EekSection, eek_section, EEK_TYPE_CONTAINER)
static gint static gint
eek_section_real_get_n_rows (EekSection *self) eek_section_real_get_n_rows (EekSection *self)
{ {
EekSectionPrivate *priv = EEK_SECTION_GET_PRIVATE(self); EekSectionPrivate *priv = eek_section_get_instance_private (self);
return g_slist_length (priv->rows); return g_slist_length (priv->rows);
} }
@ -85,7 +80,7 @@ eek_section_real_add_row (EekSection *self,
gint num_columns, gint num_columns,
EekOrientation orientation) EekOrientation orientation)
{ {
EekSectionPrivate *priv = EEK_SECTION_GET_PRIVATE(self); EekSectionPrivate *priv = eek_section_get_instance_private (self);
EekRow *row; EekRow *row;
row = g_slice_new (EekRow); row = g_slice_new (EekRow);
@ -100,7 +95,7 @@ eek_section_real_get_row (EekSection *self,
gint *num_columns, gint *num_columns,
EekOrientation *orientation) EekOrientation *orientation)
{ {
EekSectionPrivate *priv = EEK_SECTION_GET_PRIVATE(self); EekSectionPrivate *priv = eek_section_get_instance_private (self);
EekRow *row; EekRow *row;
row = g_slist_nth_data (priv->rows, index); row = g_slist_nth_data (priv->rows, index);
@ -127,9 +122,10 @@ on_unlocked (EekKey *key,
static EekKey * static EekKey *
eek_section_real_create_key (EekSection *self, eek_section_real_create_key (EekSection *self,
guint keycode, const gchar *name,
gint keycode,
gint column_index, gint column_index,
guint row_index) gint row_index)
{ {
EekKey *key; EekKey *key;
gint num_rows; gint num_rows;
@ -138,11 +134,14 @@ eek_section_real_create_key (EekSection *self,
num_rows = eek_section_get_n_rows (self); num_rows = eek_section_get_n_rows (self);
g_return_val_if_fail (0 <= row_index && row_index < num_rows, NULL); g_return_val_if_fail (0 <= row_index && row_index < num_rows, NULL);
row = g_slist_nth_data (self->priv->rows, row_index); EekSectionPrivate *priv = eek_section_get_instance_private (self);
row = g_slist_nth_data (priv->rows, row_index);
if (row->num_columns < column_index + 1) if (row->num_columns < column_index + 1)
row->num_columns = column_index + 1; row->num_columns = column_index + 1;
key = g_object_new (EEK_TYPE_KEY, key = g_object_new (EEK_TYPE_KEY,
"name", name,
"keycode", keycode, "keycode", keycode,
"column", column_index, "column", column_index,
"row", row_index, "row", row_index,
@ -158,7 +157,7 @@ eek_section_real_create_key (EekSection *self,
static void static void
set_level_from_modifiers (EekSection *self) set_level_from_modifiers (EekSection *self)
{ {
EekSectionPrivate *priv = EEK_SECTION_GET_PRIVATE(self); EekSectionPrivate *priv = eek_section_get_instance_private (self);
EekKeyboard *keyboard; EekKeyboard *keyboard;
EekModifierType num_lock_mask; EekModifierType num_lock_mask;
gint level = -1; gint level = -1;
@ -173,7 +172,7 @@ set_level_from_modifiers (EekSection *self)
static void static void
eek_section_real_key_pressed (EekSection *self, EekKey *key) eek_section_real_key_pressed (EekSection *self, EekKey *key)
{ {
EekSectionPrivate *priv = EEK_SECTION_GET_PRIVATE(self); EekSectionPrivate *priv = eek_section_get_instance_private (self);
EekSymbol *symbol; EekSymbol *symbol;
EekKeyboard *keyboard; EekKeyboard *keyboard;
EekModifierBehavior behavior; EekModifierBehavior behavior;
@ -195,7 +194,7 @@ eek_section_real_key_pressed (EekSection *self, EekKey *key)
static void static void
eek_section_real_key_released (EekSection *self, EekKey *key) eek_section_real_key_released (EekSection *self, EekKey *key)
{ {
EekSectionPrivate *priv = EEK_SECTION_GET_PRIVATE(self); EekSectionPrivate *priv = eek_section_get_instance_private (self);
EekSymbol *symbol; EekSymbol *symbol;
EekKeyboard *keyboard; EekKeyboard *keyboard;
EekModifierBehavior behavior; EekModifierBehavior behavior;
@ -225,7 +224,8 @@ eek_section_real_key_released (EekSection *self, EekKey *key)
static void static void
eek_section_finalize (GObject *object) eek_section_finalize (GObject *object)
{ {
EekSectionPrivate *priv = EEK_SECTION_GET_PRIVATE(object); EekSection *self = EEK_SECTION (object);
EekSectionPrivate *priv = eek_section_get_instance_private (self);
GSList *head; GSList *head;
for (head = priv->rows; head; head = g_slist_next (head)) for (head = priv->rows; head; head = g_slist_next (head))
@ -291,8 +291,6 @@ eek_section_class_init (EekSectionClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec; GParamSpec *pspec;
g_type_class_add_private (gobject_class, sizeof (EekSectionPrivate));
klass->get_n_rows = eek_section_real_get_n_rows; klass->get_n_rows = eek_section_real_get_n_rows;
klass->add_row = eek_section_real_add_row; klass->add_row = eek_section_real_add_row;
klass->get_row = eek_section_real_get_row; klass->get_row = eek_section_real_get_row;
@ -367,7 +365,7 @@ eek_section_class_init (EekSectionClass *klass)
static void static void
eek_section_init (EekSection *self) eek_section_init (EekSection *self)
{ {
self->priv = EEK_SECTION_GET_PRIVATE (self); /* void */
} }
/** /**
@ -382,8 +380,11 @@ eek_section_set_angle (EekSection *section,
gint angle) gint angle)
{ {
g_return_if_fail (EEK_IS_SECTION(section)); g_return_if_fail (EEK_IS_SECTION(section));
if (section->priv->angle != angle) {
section->priv->angle = angle; EekSectionPrivate *priv = eek_section_get_instance_private (section);
if (priv->angle != angle) {
priv->angle = angle;
g_object_notify (G_OBJECT(section), "angle"); g_object_notify (G_OBJECT(section), "angle");
} }
} }
@ -398,7 +399,10 @@ gint
eek_section_get_angle (EekSection *section) eek_section_get_angle (EekSection *section)
{ {
g_return_val_if_fail (EEK_IS_SECTION(section), -1); g_return_val_if_fail (EEK_IS_SECTION(section), -1);
return section->priv->angle;
EekSectionPrivate *priv = eek_section_get_instance_private (section);
return priv->angle;
} }
/** /**
@ -459,6 +463,7 @@ eek_section_get_row (EekSection *section,
/** /**
* eek_section_create_key: * eek_section_create_key:
* @section: an #EekSection * @section: an #EekSection
* @name: a name
* @keycode: a keycode * @keycode: a keycode
* @column: the column index of the key * @column: the column index of the key
* @row: the row index of the key * @row: the row index of the key
@ -469,19 +474,32 @@ eek_section_get_row (EekSection *section,
*/ */
EekKey * EekKey *
eek_section_create_key (EekSection *section, eek_section_create_key (EekSection *section,
guint keycode, const gchar *name,
gint keycode,
gint column, gint column,
gint row) gint row)
{ {
g_return_val_if_fail (EEK_IS_SECTION(section), NULL); g_return_val_if_fail (EEK_IS_SECTION(section), NULL);
return EEK_SECTION_GET_CLASS(section)->create_key (section, return EEK_SECTION_GET_CLASS(section)->create_key (section,
name,
keycode, keycode,
column, column,
row); row);
} }
static void keysizer(EekElement *element, gpointer user_data) { const double keyspacing = 4.0;
struct keys_info {
uint count;
double total_width;
double biggest_height;
};
static void
keysizer(EekElement *element, gpointer user_data)
{
EekKey *key = EEK_KEY(element); EekKey *key = EEK_KEY(element);
EekKeyboard *keyboard = EEK_KEYBOARD(user_data); EekKeyboard *keyboard = EEK_KEYBOARD(user_data);
uint oref = eek_key_get_oref (key); uint oref = eek_key_get_oref (key);
EekOutline *outline = eek_keyboard_get_outline (keyboard, oref); EekOutline *outline = eek_keyboard_get_outline (keyboard, oref);
@ -512,13 +530,16 @@ static void keysizer(EekElement *element, gpointer user_data) {
} }
} }
struct keys_info { static void
uint count; keycounter (EekElement *element, gpointer user_data)
double total_width; {
double biggest_height; EekKey *key = EEK_KEY(element);
};
/* Skip keys without labels for the current level. This causes those
keys to be hidden in the visible layout. */
if (!eek_key_has_label(key))
return;
static void keycounter (EekElement *element, gpointer user_data) {
struct keys_info *data = user_data; struct keys_info *data = user_data;
data->count++; data->count++;
EekBounds key_bounds = {0}; EekBounds key_bounds = {0};
@ -529,9 +550,15 @@ static void keycounter (EekElement *element, gpointer user_data) {
} }
} }
const double keyspacing = 4.0; static void
keyplacer(EekElement *element, gpointer user_data)
{
EekKey *key = EEK_KEY(element);
/* Skip keys without labels for the current level. */
if (!eek_key_has_label(key))
return;
static void keyplacer(EekElement *element, gpointer user_data) {
double *current_offset = user_data; double *current_offset = user_data;
EekBounds key_bounds = {0}; EekBounds key_bounds = {0};
eek_element_get_bounds(element, &key_bounds); eek_element_get_bounds(element, &key_bounds);
@ -541,7 +568,8 @@ static void keyplacer(EekElement *element, gpointer user_data) {
*current_offset += key_bounds.width + keyspacing; *current_offset += key_bounds.width + keyspacing;
} }
void eek_section_place_keys(EekSection *section, EekKeyboard *keyboard) void
eek_section_place_keys(EekSection *section, EekKeyboard *keyboard)
{ {
eek_container_foreach_child(EEK_CONTAINER(section), keysizer, keyboard); eek_container_foreach_child(EEK_CONTAINER(section), keysizer, keyboard);

View File

@ -32,28 +32,7 @@
G_BEGIN_DECLS G_BEGIN_DECLS
#define EEK_TYPE_SECTION (eek_section_get_type()) #define EEK_TYPE_SECTION (eek_section_get_type())
#define EEK_SECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEK_TYPE_SECTION, EekSection)) G_DECLARE_DERIVABLE_TYPE(EekSection, eek_section, EEK, SECTION, EekContainer)
#define EEK_SECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEK_TYPE_SECTION, EekSectionClass))
#define EEK_IS_SECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEK_TYPE_SECTION))
#define EEK_IS_SECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_SECTION))
#define EEK_SECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_SECTION, EekSectionClass))
typedef struct _EekSectionClass EekSectionClass;
typedef struct _EekSectionPrivate EekSectionPrivate;
/**
* EekSection:
*
* The #EekSection structure contains only private data and should
* only be accessed using the provided API.
*/
struct _EekSection
{
/*< private >*/
EekContainer parent;
EekSectionPrivate *priv;
};
/** /**
* EekSectionClass: * EekSectionClass:
@ -83,7 +62,8 @@ struct _EekSectionClass
EekOrientation *orientation); EekOrientation *orientation);
EekKey *(* create_key) (EekSection *self, EekKey *(* create_key) (EekSection *self,
guint keycode, const gchar *name,
gint keycode,
gint row, gint row,
gint column); gint column);
@ -120,7 +100,8 @@ void eek_section_get_row (EekSection *section,
EekOrientation *orientation); EekOrientation *orientation);
EekKey *eek_section_create_key (EekSection *section, EekKey *eek_section_create_key (EekSection *section,
guint keycode, const gchar *name,
gint keycode,
gint column, gint column,
gint row); gint row);

View File

@ -27,9 +27,7 @@
* method. * method.
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */
#include "eek-serializable.h" #include "eek-serializable.h"

View File

@ -25,9 +25,7 @@
* The #EekSymbolClass class represents a symbol assigned to a key. * The #EekSymbolClass class represents a symbol assigned to a key.
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */
#include "eek-symbol.h" #include "eek-symbol.h"
#include "eek-serializable.h" #include "eek-serializable.h"
@ -44,29 +42,31 @@ enum {
PROP_LAST PROP_LAST
}; };
struct _EekSymbolPrivate { typedef struct _EekSymbolPrivate
{
gchar *name; gchar *name;
gchar *label; gchar *label;
EekSymbolCategory category; EekSymbolCategory category;
EekModifierType modifier_mask; EekModifierType modifier_mask;
gchar *icon_name; gchar *icon_name;
gchar *tooltip; gchar *tooltip;
}; } EekSymbolPrivate;
static void eek_serializable_iface_init (EekSerializableIface *iface); static void eek_serializable_iface_init (EekSerializableIface *iface);
G_DEFINE_TYPE_WITH_CODE (EekSymbol, eek_symbol, G_TYPE_OBJECT, G_DEFINE_TYPE_EXTENDED (EekSymbol,
G_IMPLEMENT_INTERFACE (EEK_TYPE_SERIALIZABLE, eek_symbol,
eek_serializable_iface_init)); G_TYPE_OBJECT,
0, /* GTypeFlags */
#define EEK_SYMBOL_GET_PRIVATE(obj) \ G_ADD_PRIVATE (EekSymbol)
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_SYMBOL, EekSymbolPrivate)) G_IMPLEMENT_INTERFACE (EEK_TYPE_SERIALIZABLE,
eek_serializable_iface_init))
static void static void
eek_symbol_real_serialize (EekSerializable *self, eek_symbol_real_serialize (EekSerializable *self,
GVariantBuilder *builder) GVariantBuilder *builder)
{ {
EekSymbolPrivate *priv = EEK_SYMBOL_GET_PRIVATE(self); EekSymbolPrivate *priv = eek_symbol_get_instance_private (EEK_SYMBOL (self));
#define NOTNULL(s) ((s) != NULL ? (s) : "") #define NOTNULL(s) ((s) != NULL ? (s) : "")
g_variant_builder_add (builder, "s", NOTNULL(priv->name)); g_variant_builder_add (builder, "s", NOTNULL(priv->name));
g_variant_builder_add (builder, "s", NOTNULL(priv->label)); g_variant_builder_add (builder, "s", NOTNULL(priv->label));
@ -82,7 +82,7 @@ eek_symbol_real_deserialize (EekSerializable *self,
GVariant *variant, GVariant *variant,
gsize index) gsize index)
{ {
EekSymbolPrivate *priv = EEK_SYMBOL_GET_PRIVATE(self); EekSymbolPrivate *priv = eek_symbol_get_instance_private (EEK_SYMBOL (self));
g_variant_get_child (variant, index++, "s", &priv->name); g_variant_get_child (variant, index++, "s", &priv->name);
g_variant_get_child (variant, index++, "s", &priv->label); g_variant_get_child (variant, index++, "s", &priv->label);
@ -172,7 +172,8 @@ eek_symbol_get_property (GObject *object,
static void static void
eek_symbol_finalize (GObject *object) eek_symbol_finalize (GObject *object)
{ {
EekSymbolPrivate *priv = EEK_SYMBOL_GET_PRIVATE(object); EekSymbol *self = EEK_SYMBOL (object);
EekSymbolPrivate *priv = eek_symbol_get_instance_private (self);
g_free (priv->name); g_free (priv->name);
g_free (priv->label); g_free (priv->label);
@ -187,8 +188,6 @@ eek_symbol_class_init (EekSymbolClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec; GParamSpec *pspec;
g_type_class_add_private (gobject_class, sizeof (EekSymbolPrivate));
gobject_class->set_property = eek_symbol_set_property; gobject_class->set_property = eek_symbol_set_property;
gobject_class->get_property = eek_symbol_get_property; gobject_class->get_property = eek_symbol_get_property;
gobject_class->finalize = eek_symbol_finalize; gobject_class->finalize = eek_symbol_finalize;
@ -241,9 +240,8 @@ eek_symbol_class_init (EekSymbolClass *klass)
static void static void
eek_symbol_init (EekSymbol *self) eek_symbol_init (EekSymbol *self)
{ {
EekSymbolPrivate *priv; EekSymbolPrivate *priv = eek_symbol_get_instance_private (self);
priv = self->priv = EEK_SYMBOL_GET_PRIVATE(self);
priv->category = EEK_SYMBOL_CATEGORY_UNKNOWN; priv->category = EEK_SYMBOL_CATEGORY_UNKNOWN;
} }
@ -270,11 +268,10 @@ void
eek_symbol_set_name (EekSymbol *symbol, eek_symbol_set_name (EekSymbol *symbol,
const gchar *name) const gchar *name)
{ {
EekSymbolPrivate *priv;
g_return_if_fail (EEK_IS_SYMBOL(symbol)); g_return_if_fail (EEK_IS_SYMBOL(symbol));
priv = EEK_SYMBOL_GET_PRIVATE(symbol); EekSymbolPrivate *priv = eek_symbol_get_instance_private (symbol);
g_free (priv->name); g_free (priv->name);
priv->name = g_strdup (name); priv->name = g_strdup (name);
} }
@ -288,11 +285,10 @@ eek_symbol_set_name (EekSymbol *symbol,
const gchar * const gchar *
eek_symbol_get_name (EekSymbol *symbol) eek_symbol_get_name (EekSymbol *symbol)
{ {
EekSymbolPrivate *priv;
g_return_val_if_fail (EEK_IS_SYMBOL(symbol), NULL); g_return_val_if_fail (EEK_IS_SYMBOL(symbol), NULL);
priv = EEK_SYMBOL_GET_PRIVATE(symbol); EekSymbolPrivate *priv = eek_symbol_get_instance_private (symbol);
if (priv->name == NULL || *priv->name == '\0') if (priv->name == NULL || *priv->name == '\0')
return NULL; return NULL;
return priv->name; return priv->name;
@ -309,11 +305,10 @@ void
eek_symbol_set_label (EekSymbol *symbol, eek_symbol_set_label (EekSymbol *symbol,
const gchar *label) const gchar *label)
{ {
EekSymbolPrivate *priv;
g_return_if_fail (EEK_IS_SYMBOL(symbol)); g_return_if_fail (EEK_IS_SYMBOL(symbol));
priv = EEK_SYMBOL_GET_PRIVATE(symbol); EekSymbolPrivate *priv = eek_symbol_get_instance_private (symbol);
g_free (priv->label); g_free (priv->label);
priv->label = g_strdup (label); priv->label = g_strdup (label);
} }
@ -327,11 +322,10 @@ eek_symbol_set_label (EekSymbol *symbol,
const gchar * const gchar *
eek_symbol_get_label (EekSymbol *symbol) eek_symbol_get_label (EekSymbol *symbol)
{ {
EekSymbolPrivate *priv;
g_return_val_if_fail (EEK_IS_SYMBOL(symbol), NULL); g_return_val_if_fail (EEK_IS_SYMBOL(symbol), NULL);
priv = EEK_SYMBOL_GET_PRIVATE(symbol); EekSymbolPrivate *priv = eek_symbol_get_instance_private (symbol);
if (priv->label == NULL || *priv->label == '\0') if (priv->label == NULL || *priv->label == '\0')
return NULL; return NULL;
return priv->label; return priv->label;
@ -348,11 +342,10 @@ void
eek_symbol_set_category (EekSymbol *symbol, eek_symbol_set_category (EekSymbol *symbol,
EekSymbolCategory category) EekSymbolCategory category)
{ {
EekSymbolPrivate *priv;
g_return_if_fail (EEK_IS_SYMBOL(symbol)); g_return_if_fail (EEK_IS_SYMBOL(symbol));
priv = EEK_SYMBOL_GET_PRIVATE(symbol); EekSymbolPrivate *priv = eek_symbol_get_instance_private (symbol);
priv->category = category; priv->category = category;
} }
@ -365,11 +358,10 @@ eek_symbol_set_category (EekSymbol *symbol,
EekSymbolCategory EekSymbolCategory
eek_symbol_get_category (EekSymbol *symbol) eek_symbol_get_category (EekSymbol *symbol)
{ {
EekSymbolPrivate *priv;
g_return_val_if_fail (EEK_IS_SYMBOL(symbol), EEK_SYMBOL_CATEGORY_UNKNOWN); g_return_val_if_fail (EEK_IS_SYMBOL(symbol), EEK_SYMBOL_CATEGORY_UNKNOWN);
priv = EEK_SYMBOL_GET_PRIVATE(symbol); EekSymbolPrivate *priv = eek_symbol_get_instance_private (symbol);
return priv->category; return priv->category;
} }
@ -384,11 +376,10 @@ void
eek_symbol_set_modifier_mask (EekSymbol *symbol, eek_symbol_set_modifier_mask (EekSymbol *symbol,
EekModifierType mask) EekModifierType mask)
{ {
EekSymbolPrivate *priv;
g_return_if_fail (EEK_IS_SYMBOL(symbol)); g_return_if_fail (EEK_IS_SYMBOL(symbol));
priv = EEK_SYMBOL_GET_PRIVATE(symbol); EekSymbolPrivate *priv = eek_symbol_get_instance_private (symbol);
priv->modifier_mask = mask; priv->modifier_mask = mask;
} }
@ -401,11 +392,10 @@ eek_symbol_set_modifier_mask (EekSymbol *symbol,
EekModifierType EekModifierType
eek_symbol_get_modifier_mask (EekSymbol *symbol) eek_symbol_get_modifier_mask (EekSymbol *symbol)
{ {
EekSymbolPrivate *priv;
g_return_val_if_fail (EEK_IS_SYMBOL(symbol), 0); g_return_val_if_fail (EEK_IS_SYMBOL(symbol), 0);
priv = EEK_SYMBOL_GET_PRIVATE(symbol); EekSymbolPrivate *priv = eek_symbol_get_instance_private (symbol);
return priv->modifier_mask; return priv->modifier_mask;
} }
@ -433,11 +423,10 @@ void
eek_symbol_set_icon_name (EekSymbol *symbol, eek_symbol_set_icon_name (EekSymbol *symbol,
const gchar *icon_name) const gchar *icon_name)
{ {
EekSymbolPrivate *priv;
g_return_if_fail (EEK_IS_SYMBOL(symbol)); g_return_if_fail (EEK_IS_SYMBOL(symbol));
priv = EEK_SYMBOL_GET_PRIVATE(symbol); EekSymbolPrivate *priv = eek_symbol_get_instance_private (symbol);
g_free (priv->icon_name); g_free (priv->icon_name);
priv->icon_name = g_strdup (icon_name); priv->icon_name = g_strdup (icon_name);
} }
@ -451,11 +440,10 @@ eek_symbol_set_icon_name (EekSymbol *symbol,
const gchar * const gchar *
eek_symbol_get_icon_name (EekSymbol *symbol) eek_symbol_get_icon_name (EekSymbol *symbol)
{ {
EekSymbolPrivate *priv;
g_return_val_if_fail (EEK_IS_SYMBOL(symbol), NULL); g_return_val_if_fail (EEK_IS_SYMBOL(symbol), NULL);
priv = EEK_SYMBOL_GET_PRIVATE(symbol); EekSymbolPrivate *priv = eek_symbol_get_instance_private (symbol);
if (priv->icon_name == NULL || *priv->icon_name == '\0') if (priv->icon_name == NULL || *priv->icon_name == '\0')
return NULL; return NULL;
return priv->icon_name; return priv->icon_name;
@ -472,11 +460,10 @@ void
eek_symbol_set_tooltip (EekSymbol *symbol, eek_symbol_set_tooltip (EekSymbol *symbol,
const gchar *tooltip) const gchar *tooltip)
{ {
EekSymbolPrivate *priv;
g_return_if_fail (EEK_IS_SYMBOL(symbol)); g_return_if_fail (EEK_IS_SYMBOL(symbol));
priv = EEK_SYMBOL_GET_PRIVATE(symbol); EekSymbolPrivate *priv = eek_symbol_get_instance_private (symbol);
g_free (priv->tooltip); g_free (priv->tooltip);
priv->tooltip = g_strdup (tooltip); priv->tooltip = g_strdup (tooltip);
} }
@ -490,11 +477,10 @@ eek_symbol_set_tooltip (EekSymbol *symbol,
const gchar * const gchar *
eek_symbol_get_tooltip (EekSymbol *symbol) eek_symbol_get_tooltip (EekSymbol *symbol)
{ {
EekSymbolPrivate *priv;
g_return_val_if_fail (EEK_IS_SYMBOL(symbol), NULL); g_return_val_if_fail (EEK_IS_SYMBOL(symbol), NULL);
priv = EEK_SYMBOL_GET_PRIVATE(symbol); EekSymbolPrivate *priv = eek_symbol_get_instance_private (symbol);
if (priv->tooltip == NULL || *priv->tooltip == '\0') if (priv->tooltip == NULL || *priv->tooltip == '\0')
return NULL; return NULL;
return priv->tooltip; return priv->tooltip;

View File

@ -59,27 +59,7 @@ typedef enum {
} EekSymbolCategory; } EekSymbolCategory;
#define EEK_TYPE_SYMBOL (eek_symbol_get_type()) #define EEK_TYPE_SYMBOL (eek_symbol_get_type())
#define EEK_SYMBOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEK_TYPE_SYMBOL, EekSymbol)) G_DECLARE_DERIVABLE_TYPE(EekSymbol, eek_symbol, EEK, SYMBOL, GObject)
#define EEK_SYMBOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEK_TYPE_SYMBOL, EekSymbolClass))
#define EEK_IS_SYMBOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEK_TYPE_SYMBOL))
#define EEK_IS_SYMBOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_SYMBOL))
#define EEK_SYMBOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_SYMBOL, EekSymbolClass))
typedef struct _EekSymbolClass EekSymbolClass;
typedef struct _EekSymbolPrivate EekSymbolPrivate;
/**
* EekSymbol:
*
* The #EekSymbol structure contains only private data and should only
* be accessed using the provided API.
*/
struct _EekSymbol {
/*< private >*/
GObject parent;
EekSymbolPrivate *priv;
};
/** /**
* EekSymbolClass: * EekSymbolClass:

View File

@ -23,9 +23,7 @@
* @short_description: an #EekText represents a text symbol * @short_description: an #EekText represents a text symbol
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */
#include "eek-text.h" #include "eek-text.h"
#include "eek-serializable.h" #include "eek-serializable.h"
@ -36,18 +34,20 @@ enum {
PROP_LAST PROP_LAST
}; };
struct _EekTextPrivate { typedef struct _EekTextPrivate
{
gchar *text; gchar *text;
}; } EekTextPrivate;
static void eek_serializable_iface_init (EekSerializableIface *iface); static void eek_serializable_iface_init (EekSerializableIface *iface);
G_DEFINE_TYPE_WITH_CODE (EekText, eek_text, EEK_TYPE_SYMBOL, G_DEFINE_TYPE_EXTENDED (EekText,
G_IMPLEMENT_INTERFACE (EEK_TYPE_SERIALIZABLE, eek_text,
eek_serializable_iface_init)); EEK_TYPE_SYMBOL,
0, /* GTypeFlags */
#define EEK_TEXT_GET_PRIVATE(obj) \ G_ADD_PRIVATE (EekText)
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_TEXT, EekTextPrivate)) G_IMPLEMENT_INTERFACE (EEK_TYPE_SERIALIZABLE,
eek_serializable_iface_init))
static EekSerializableIface *eek_text_parent_serializable_iface; static EekSerializableIface *eek_text_parent_serializable_iface;
@ -55,7 +55,7 @@ static void
eek_text_real_serialize (EekSerializable *self, eek_text_real_serialize (EekSerializable *self,
GVariantBuilder *builder) GVariantBuilder *builder)
{ {
EekTextPrivate *priv = EEK_TEXT_GET_PRIVATE(self); EekTextPrivate *priv = eek_text_get_instance_private (EEK_TEXT (self));
eek_text_parent_serializable_iface->serialize (self, builder); eek_text_parent_serializable_iface->serialize (self, builder);
@ -67,7 +67,7 @@ eek_text_real_deserialize (EekSerializable *self,
GVariant *variant, GVariant *variant,
gsize index) gsize index)
{ {
EekTextPrivate *priv = EEK_TEXT_GET_PRIVATE(self); EekTextPrivate *priv = eek_text_get_instance_private (EEK_TEXT (self));
index = eek_text_parent_serializable_iface->deserialize (self, index = eek_text_parent_serializable_iface->deserialize (self,
variant, variant,
@ -93,7 +93,9 @@ eek_text_set_property (GObject *object,
const GValue *value, const GValue *value,
GParamSpec *pspec) GParamSpec *pspec)
{ {
EekTextPrivate *priv = EEK_TEXT_GET_PRIVATE(object); EekText *self = EEK_TEXT (object);
EekTextPrivate *priv = eek_text_get_instance_private (self);
switch (prop_id) { switch (prop_id) {
case PROP_TEXT: case PROP_TEXT:
g_free (priv->text); g_free (priv->text);
@ -107,11 +109,13 @@ eek_text_set_property (GObject *object,
static void static void
eek_text_get_property (GObject *object, eek_text_get_property (GObject *object,
guint prop_id, guint prop_id,
GValue *value, GValue *value,
GParamSpec *pspec) GParamSpec *pspec)
{ {
EekTextPrivate *priv = EEK_TEXT_GET_PRIVATE(object); EekText *self = EEK_TEXT (object);
EekTextPrivate *priv = eek_text_get_instance_private (self);
switch (prop_id) { switch (prop_id) {
case PROP_TEXT: case PROP_TEXT:
g_value_set_string (value, priv->text); g_value_set_string (value, priv->text);
@ -125,7 +129,8 @@ eek_text_get_property (GObject *object,
static void static void
eek_text_finalize (GObject *object) eek_text_finalize (GObject *object)
{ {
EekTextPrivate *priv = EEK_TEXT_GET_PRIVATE(object); EekText *self = EEK_TEXT (object);
EekTextPrivate *priv = eek_text_get_instance_private (self);
g_free (priv->text); g_free (priv->text);
G_OBJECT_CLASS (eek_text_parent_class)->finalize (object); G_OBJECT_CLASS (eek_text_parent_class)->finalize (object);
@ -137,8 +142,6 @@ eek_text_class_init (EekTextClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec; GParamSpec *pspec;
g_type_class_add_private (gobject_class, sizeof (EekTextPrivate));
gobject_class->set_property = eek_text_set_property; gobject_class->set_property = eek_text_set_property;
gobject_class->get_property = eek_text_get_property; gobject_class->get_property = eek_text_get_property;
gobject_class->finalize = eek_text_finalize; gobject_class->finalize = eek_text_finalize;
@ -154,7 +157,7 @@ eek_text_class_init (EekTextClass *klass)
static void static void
eek_text_init (EekText *self) eek_text_init (EekText *self)
{ {
self->priv = EEK_TEXT_GET_PRIVATE(self); /* void */
} }
EekText * EekText *
@ -176,7 +179,7 @@ eek_text_new (const gchar *text)
const gchar * const gchar *
eek_text_get_text (EekText *text) eek_text_get_text (EekText *text)
{ {
EekTextPrivate *priv = EEK_TEXT_GET_PRIVATE(text); EekTextPrivate *priv = eek_text_get_instance_private (text);
return priv->text; return priv->text;
} }

View File

@ -30,27 +30,7 @@
G_BEGIN_DECLS G_BEGIN_DECLS
#define EEK_TYPE_TEXT (eek_text_get_type()) #define EEK_TYPE_TEXT (eek_text_get_type())
#define EEK_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEK_TYPE_TEXT, EekText)) G_DECLARE_DERIVABLE_TYPE(EekText, eek_text, EEK, TEXT, EekSymbol)
#define EEK_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEK_TYPE_TEXT, EekTextClass))
#define EEK_IS_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEK_TYPE_TEXT))
#define EEK_IS_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_TEXT))
#define EEK_TEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_TEXT, EekTextClass))
typedef struct _EekTextClass EekTextClass;
typedef struct _EekTextPrivate EekTextPrivate;
/**
* EekText:
*
* The #EekText structure contains only private data and should only
* be accessed using the provided API.
*/
struct _EekText {
/*< private >*/
EekSymbol parent;
EekTextPrivate *priv;
};
struct _EekTextClass { struct _EekTextClass {
/*< private >*/ /*< private >*/

View File

@ -19,9 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */
#include "eek-theme.h" #include "eek-theme.h"
#include "eek-theme-context.h" #include "eek-theme-context.h"

View File

@ -23,9 +23,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -89,9 +87,6 @@ static void eek_theme_node_finalize (GObject *object);
static const EekColor BLACK_COLOR = { 0, 0, 0, 0xff }; static const EekColor BLACK_COLOR = { 0, 0, 0, 0xff };
static const EekColor TRANSPARENT_COLOR = { 0, 0, 0, 0 }; static const EekColor TRANSPARENT_COLOR = { 0, 0, 0, 0 };
static const EekColor DEFAULT_SUCCESS_COLOR = { 0x4e, 0x9a, 0x06, 0xff };
static const EekColor DEFAULT_WARNING_COLOR = { 0xf5, 0x79, 0x3e, 0xff };
static const EekColor DEFAULT_ERROR_COLOR = { 0xcc, 0x00, 0x00, 0xff };
static void static void
eek_theme_node_init (EekThemeNode *self) eek_theme_node_init (EekThemeNode *self)

View File

@ -43,6 +43,7 @@
* Copyright (C) 2003-2004 Dodji Seketeli. All Rights Reserved. * Copyright (C) 2003-2004 Dodji Seketeli. All Rights Reserved.
*/ */
#define G_LOG_DOMAIN "eek-theme"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -166,103 +167,65 @@ eek_theme_class_init (EekThemeClass *klass)
} }
/* This is a workaround for a bug in libcroco < 0.6.2 where
* function starting with 'r' (and 'u') are misparsed. We work
* around this by exploiting the fact that libcroco is incomformant
* with the CSS-spec and case sensitive and pre-convert all
* occurrences of rgba to RGBA. Then we make our own parsing
* code check for RGBA as well.
*/
#if LIBCROCO_VERSION_NUMBER < 602
static gboolean
is_identifier_character (char c)
{
/* Actual CSS rules allow for unicode > 0x00a1 and escaped
* characters, but we'll assume we won't do that in our stylesheets
* or at least not next to the string 'rgba'.
*/
return g_ascii_isalnum(c) || c == '-' || c == '_';
}
static void
convert_rgba_RGBA (char *buf)
{
char *p;
p = strstr (buf, "rgba");
while (p)
{
/* Check if this looks like a complete token; this is to
* avoiding mangling, say, a selector '.rgba-entry' */
if (!((p > buf && is_identifier_character (*(p - 1))) ||
(is_identifier_character (*(p + 4)))))
memcpy(p, "RGBA", 4);
p += 4;
p = strstr (p, "rgba");
}
}
static CRStyleSheet *
parse_stylesheet (const char *filename,
GError **error)
{
enum CRStatus status;
char *contents;
gsize length;
CRStyleSheet *stylesheet = NULL;
if (filename == NULL)
return NULL;
if (!g_file_get_contents (filename, &contents, &length, error))
return NULL;
convert_rgba_RGBA (contents);
status = cr_om_parser_simply_parse_buf ((const guchar *) contents,
length,
CR_UTF_8,
&stylesheet);
g_free (contents);
if (status != CR_OK)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Error parsing stylesheet '%s'; errcode:%d", filename, status);
return NULL;
}
return stylesheet;
}
CRDeclaration *
_eek_theme_parse_declaration_list (const char *str)
{
char *copy = g_strdup (str);
CRDeclaration *result;
convert_rgba_RGBA (copy);
result = cr_declaration_parse_list_from_buf ((const guchar *)copy,
CR_UTF_8);
g_free (copy);
return result;
}
#else /* LIBCROCO_VERSION_NUMBER >= 602 */
static CRStyleSheet * static CRStyleSheet *
parse_stylesheet (const char *filename, parse_stylesheet (const char *filename,
GError **error) GError **error)
{ {
enum CRStatus status; enum CRStatus status;
CRStyleSheet *stylesheet; CRStyleSheet *stylesheet;
g_autoptr (GFileInputStream) stream = NULL;
g_autoptr (GFileInfo) info = NULL;
g_autoptr (GFile) file = NULL;
g_autofree guchar* contents = NULL;
goffset size;
gsize out = 0;
GError *err = NULL;
if (filename == NULL) if (filename == NULL)
return NULL; return NULL;
status = cr_om_parser_simply_parse_file ((const guchar *) filename, g_debug ("Parsing %s", filename);
CR_UTF_8, if (g_strcmp0 (filename, "resource://") > 0) {
&stylesheet); file = g_file_new_for_uri (filename);
stream = g_file_read (file, NULL, &err);
if (!stream) {
g_warning ("Failed to open %s: %s", filename, err->message);
g_clear_error (&err);
return NULL;
}
info = g_file_input_stream_query_info (stream,
G_FILE_ATTRIBUTE_STANDARD_SIZE,
NULL,
&err);
if (!info) {
g_warning ("Failed to stat %s: %s", filename, err->message);
g_clear_error (&err);
return NULL;
}
size = g_file_info_get_size (info);
contents = g_malloc0 (size);
if (!g_input_stream_read_all (G_INPUT_STREAM (stream),
contents,
size,
&out,
NULL,
&err)) {
g_warning ("Failed to read %s: %s", filename, err->message);
g_clear_error (&err);
return NULL;
}
status = cr_om_parser_simply_parse_buf (contents,
size,
CR_UTF_8,
&stylesheet);
} else {
status = cr_om_parser_simply_parse_file ((const guchar *) filename,
CR_UTF_8,
&stylesheet);
}
if (status != CR_OK) if (status != CR_OK)
{ {
@ -280,7 +243,6 @@ _eek_theme_parse_declaration_list (const char *str)
return cr_declaration_parse_list_from_buf ((const guchar *)str, return cr_declaration_parse_list_from_buf ((const guchar *)str,
CR_UTF_8); CR_UTF_8);
} }
#endif /* LIBCROCO_VERSION_NUMBER < 602 */
/* Just g_warning for now until we have something nicer to do */ /* Just g_warning for now until we have something nicer to do */
static CRStyleSheet * static CRStyleSheet *

View File

@ -24,9 +24,7 @@
* @short_description: Miscellaneous types used in Libeek * @short_description: Miscellaneous types used in Libeek
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>

View File

@ -1,30 +0,0 @@
# Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
# Copyright (C) 2010-2011 Red Hat, Inc.
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libeek-xkb
Description: A Library to Create Keyboard-like UI (XKB Support)
URL: http://fedorahosted.org/eekboard/
Version: @VERSION@
Requires: eek-@EEK_API_VERSION@ gtk+-x11-@GTK_API_VERSION@
Libs: -L${libdir} -leek-xkb
Cflags: -I${includedir}/eek-@EEK_API_VERSION@

View File

@ -1,682 +0,0 @@
/*
* Copyright (C) 2006 Sergey V. Udaltsov <svu@gnome.org>
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
/**
* SECTION:eek-xkb-layout
* @short_description: Layout engine using XKB configuration
*
* The #EekXkbLayout inherits #EekLayout class and arranges keyboard
* elements using XKB.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include "eek-xkb-layout.h"
#include <X11/keysym.h>
#include <X11/extensions/XKBgeom.h>
#include <string.h>
#include <stdarg.h>
#include <gio/gio.h>
#include "eek-keyboard.h"
#include "eek-section.h"
#include "eek-key.h"
#include "eek-keysym.h"
#define XKB_COMPONENT_MASK (XkbGBN_GeometryMask | \
XkbGBN_KeyNamesMask | \
XkbGBN_OtherNamesMask | \
XkbGBN_SymbolsMask | \
XkbGBN_IndicatorMapMask)
static void initable_iface_init (GInitableIface *initable_iface);
G_DEFINE_TYPE_WITH_CODE (EekXkbLayout, eek_xkb_layout, EEK_TYPE_LAYOUT,
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
initable_iface_init));
#define EEK_XKB_LAYOUT_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_XKB_LAYOUT, EekXkbLayoutPrivate))
enum {
PROP_0,
PROP_DISPLAY,
PROP_LAST
};
struct _EekXkbLayoutPrivate
{
/* Configuration names that should synch'ed to the symbolic names
in priv->xkb->names. Since we use GLib's memory allocator,
don't store any address returned from the X server here. */
XkbComponentNamesRec names;
Display *display;
/* Actual XKB configuration of DISPLAY. */
XkbDescRec *xkb;
/* Hash table to cache orefs by shape address. */
GHashTable *shape_oref_hash;
gint scale_numerator;
gint scale_denominator;
};
static guint find_keycode (EekXkbLayout *layout,
gchar *key_name);
static gboolean get_keyboard_from_server (EekXkbLayout *layout,
GError **error);
static gboolean get_names_from_server (EekXkbLayout *layout,
GError **error);
static void setup_scaling (EekXkbLayout *layout,
gdouble width,
gdouble height);
G_INLINE_FUNC gint
xkb_to_pixmap_coord (EekXkbLayout *layout,
gint n)
{
EekXkbLayoutPrivate *priv = layout->priv;
return n * priv->scale_numerator / priv->scale_denominator;
}
G_INLINE_FUNC gdouble
xkb_to_pixmap_double (EekXkbLayout *layout,
gdouble d)
{
EekXkbLayoutPrivate *priv = layout->priv;
return d * priv->scale_numerator / priv->scale_denominator;
}
static void
create_key (EekXkbLayout *layout,
EekKeyboard *keyboard,
EekSection *section,
gint column,
gint row,
gdouble x,
gdouble y,
XkbKeyRec *xkbkey)
{
XkbGeometryRec *xkbgeometry;
XkbBoundsRec *xkbbounds;
XkbShapeRec *xkbshape;
XkbOutlineRec *xkboutline;
EekXkbLayoutPrivate *priv = layout->priv;
EekKey *key;
EekBounds bounds;
EekSymbolMatrix *matrix = NULL;
gchar name[XkbKeyNameLength + 1];
KeyCode keycode;
gint num_groups, num_levels;
guint oref;
gpointer v;
xkbgeometry = priv->xkb->geom;
xkbshape = &xkbgeometry->shapes[xkbkey->shape_ndx];
if (g_hash_table_lookup_extended (priv->shape_oref_hash, xkbshape,
NULL, &v)) {
oref = GPOINTER_TO_UINT(v);
} else {
EekOutline *outline;
xkboutline = xkbshape->primary == NULL ? &xkbshape->outlines[0] :
xkbshape->primary;
outline = g_slice_new (EekOutline);
outline->corner_radius = xkb_to_pixmap_coord(layout,
xkboutline->corner_radius);
if (xkboutline->num_points <= 2) { /* rectangular */
gdouble x1, y1, x2, y2;
outline->num_points = 4;
outline->points = g_slice_alloc0 (sizeof (EekPoint) *
outline->num_points);
if (xkboutline->num_points == 1) {
x1 = xkb_to_pixmap_coord(layout, xkbshape->bounds.x1);
y1 = xkb_to_pixmap_coord(layout, xkbshape->bounds.y1);
x2 = xkb_to_pixmap_coord(layout, xkboutline->points[0].x);
y2 = xkb_to_pixmap_coord(layout, xkboutline->points[0].y);
} else {
x1 = xkb_to_pixmap_coord(layout, xkboutline->points[0].x);
y1 = xkb_to_pixmap_coord(layout, xkboutline->points[0].y);
x2 = xkb_to_pixmap_coord(layout, xkboutline->points[1].x);
y2 = xkb_to_pixmap_coord(layout, xkboutline->points[1].y);
}
outline->points[0].x = outline->points[3].x = x1;
outline->points[0].y = outline->points[1].y = y1;
outline->points[1].x = outline->points[2].x = x2;
outline->points[2].y = outline->points[3].y = y2;
} else { /* polygon */
gint i;
outline->num_points = xkboutline->num_points;
outline->points = g_new0 (EekPoint, outline->num_points);
for (i = 0; i < xkboutline->num_points; i++) {
outline->points[i].x =
xkb_to_pixmap_coord(layout, xkboutline->points[i].x);
outline->points[i].y =
xkb_to_pixmap_coord(layout, xkboutline->points[i].y);
}
}
oref = eek_keyboard_add_outline (keyboard, outline);
eek_outline_free (outline);
g_hash_table_insert (priv->shape_oref_hash, xkbshape,
GUINT_TO_POINTER(oref));
}
memset (name, 0, sizeof name);
memcpy (name, xkbkey->name.name, sizeof name - 1);
xkbbounds = &xkbgeometry->shapes[xkbkey->shape_ndx].bounds;
bounds.x = xkb_to_pixmap_coord(layout, xkbbounds->x1 + x);
bounds.y = xkb_to_pixmap_coord(layout, xkbbounds->y1 + y);
bounds.width = xkb_to_pixmap_coord(layout, xkbbounds->x2 - xkbbounds->x1);
bounds.height = xkb_to_pixmap_coord(layout, xkbbounds->y2 - xkbbounds->y1);
keycode = find_keycode (layout, name);
if (keycode == EEK_INVALID_KEYCODE) {
num_groups = num_levels = 0;
matrix = eek_symbol_matrix_new (0, 0);
} else {
KeySym keysym;
gint i, j;
num_groups = XkbKeyNumGroups (priv->xkb, keycode);
num_levels = XkbKeyGroupsWidth (priv->xkb, keycode);
matrix = eek_symbol_matrix_new (num_groups, num_levels);
for (i = 0; i < num_groups; i++)
for (j = 0; j < num_levels; j++) {
EekModifierType modifier;
keysym = XkbKeySymEntry (priv->xkb, keycode, j, i);
modifier = XkbKeysymToModifiers (priv->display, keysym);
matrix->data[i * num_levels + j] =
EEK_SYMBOL(eek_keysym_new_with_modifier (keysym,
modifier));
}
}
key = eek_section_create_key (section, keycode, column, row);
eek_element_set_name (EEK_ELEMENT(key), name);
eek_element_set_bounds (EEK_ELEMENT(key), &bounds);
eek_key_set_symbol_matrix (key, matrix);
eek_symbol_matrix_free (matrix);
eek_key_set_oref (key, oref);
}
static void
create_section (EekXkbLayout *layout,
EekKeyboard *keyboard,
XkbSectionRec *xkbsection)
{
XkbGeometryRec *xkbgeometry;
EekXkbLayoutPrivate *priv;
EekSection *section;
EekBounds bounds;
gchar *name;
gfloat left, top;
gint i, j;
bounds.x = xkb_to_pixmap_coord(layout, xkbsection->left);
bounds.y = xkb_to_pixmap_coord(layout, xkbsection->top);
bounds.width = xkb_to_pixmap_coord(layout, xkbsection->width);
bounds.height = xkb_to_pixmap_coord(layout, xkbsection->height);
priv = layout->priv;
xkbgeometry = priv->xkb->geom;
section = eek_keyboard_create_section (keyboard);
name = XGetAtomName (priv->display, xkbsection->name);
eek_element_set_name (EEK_ELEMENT(section), name);
XFree (name);
eek_element_set_bounds (EEK_ELEMENT(section), &bounds);
eek_section_set_angle (section,
/* angle is in tenth of degree */
xkbsection->angle / 10);
for (i = 0; i < xkbsection->num_rows; i++) {
XkbRowRec *xkbrow;
xkbrow = &xkbsection->rows[i];
left = xkbrow->left;
top = xkbrow->top;
eek_section_add_row (section,
xkbrow->num_keys,
xkbrow->vertical ?
EEK_ORIENTATION_VERTICAL :
EEK_ORIENTATION_HORIZONTAL);
for (j = 0; j < xkbrow->num_keys; j++) {
XkbKeyRec *xkbkey;
XkbBoundsRec *xkbbounds;
xkbkey = &xkbrow->keys[j];
if (xkbrow->vertical)
top += xkbkey->gap;
else
left += xkbkey->gap;
create_key (layout, keyboard, section, j, i, left, top, xkbkey);
xkbbounds = &xkbgeometry->shapes[xkbkey->shape_ndx].bounds;
if (xkbrow->vertical)
top += xkbbounds->y2 - xkbbounds->y1;
else
left += xkbbounds->x2 - xkbbounds->x1;
}
}
}
static void
create_keyboard (EekXkbLayout *layout, EekKeyboard *keyboard)
{
EekXkbLayoutPrivate *priv = layout->priv;
XkbGeometryRec *xkbgeometry;
EekBounds bounds;
gint i;
g_return_if_fail (priv->xkb);
g_return_if_fail (priv->xkb->geom);
xkbgeometry = priv->xkb->geom;
eek_element_get_bounds (EEK_ELEMENT(keyboard), &bounds);
setup_scaling (EEK_XKB_LAYOUT(layout), bounds.width, bounds.height);
bounds.x = bounds.y = 0;
bounds.width = xkb_to_pixmap_coord(layout, xkbgeometry->width_mm);
bounds.height = xkb_to_pixmap_coord(layout, xkbgeometry->height_mm);
for (i = 0; i < xkbgeometry->num_sections; i++) {
XkbSectionRec *xkbsection;
xkbsection = &xkbgeometry->sections[i];
create_section (layout, keyboard, xkbsection);
}
eek_element_set_bounds (EEK_ELEMENT(keyboard), &bounds);
}
static EekKeyboard *
eek_xkb_layout_real_create_keyboard (EekboardContextService *manager,
EekLayout *self,
gdouble initial_width,
gdouble initial_height)
{
EekKeyboard *keyboard = g_object_new (EEK_TYPE_KEYBOARD, "layout", self, NULL);
keyboard->manager = manager;
EekBounds bounds = {
.x = 0.0,
.y = 0.0,
.width = initial_width,
.height = initial_height
};
eek_element_set_bounds (EEK_ELEMENT(keyboard), &bounds);
/* resolve modifiers dynamically assigned at run time */
EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (self);
eek_keyboard_set_num_lock_mask (keyboard,
XkbKeysymToModifiers (priv->display,
XK_Num_Lock));
eek_keyboard_set_alt_gr_mask (keyboard,
XkbKeysymToModifiers (priv->display,
XK_ISO_Level3_Shift));
if (priv->shape_oref_hash)
g_hash_table_destroy (priv->shape_oref_hash);
priv->shape_oref_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
create_keyboard (EEK_XKB_LAYOUT(self), keyboard);
g_hash_table_destroy (priv->shape_oref_hash);
return keyboard;
}
static void
eek_xkb_layout_finalize (GObject *object)
{
EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (object);
g_free (priv->names.keycodes);
g_free (priv->names.geometry);
g_free (priv->names.symbols);
XkbFreeKeyboard (priv->xkb, 0, TRUE); /* free_all = TRUE */
G_OBJECT_CLASS (eek_xkb_layout_parent_class)->finalize (object);
}
static void
eek_xkb_layout_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
EekXkbLayout *layout = EEK_XKB_LAYOUT (object);
switch (prop_id) {
case PROP_DISPLAY:
layout->priv->display = g_value_get_pointer (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
eek_xkb_layout_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
EekXkbLayout *layout = EEK_XKB_LAYOUT (object);
switch (prop_id) {
case PROP_DISPLAY:
g_value_set_pointer (value, layout->priv->display);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
eek_xkb_layout_class_init (EekXkbLayoutClass *klass)
{
EekLayoutClass *layout_class = EEK_LAYOUT_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
g_type_class_add_private (gobject_class, sizeof (EekXkbLayoutPrivate));
layout_class->create_keyboard = eek_xkb_layout_real_create_keyboard;
gobject_class->finalize = eek_xkb_layout_finalize;
gobject_class->set_property = eek_xkb_layout_set_property;
gobject_class->get_property = eek_xkb_layout_get_property;
pspec = g_param_spec_pointer ("display",
"Display",
"X Display",
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (gobject_class, PROP_DISPLAY, pspec);
}
static void
eek_xkb_layout_init (EekXkbLayout *self)
{
self->priv = EEK_XKB_LAYOUT_GET_PRIVATE (self);
}
static gboolean
get_names_from_server (EekXkbLayout *layout,
GError **error)
{
EekXkbLayoutPrivate *priv = layout->priv;
gchar *name;
XkbGetNames (priv->display, XkbAllNamesMask, priv->xkb);
if (priv->xkb->names->keycodes <= 0)
g_warning ("XKB keycodes setting is not loaded properly");
else {
name = XGetAtomName (priv->display, priv->xkb->names->keycodes);
if (!name)
g_warning ("Can't get the name of keycodes");
else if (!priv->names.keycodes ||
g_strcmp0 (name, priv->names.keycodes)) {
g_free (priv->names.keycodes);
priv->names.keycodes = g_strdup (name);
XFree (name);
}
}
if (priv->xkb->names->geometry <= 0)
g_warning ("XKB geometry setting is not loaded");
else {
name = XGetAtomName (priv->display, priv->xkb->names->geometry);
if (!name)
g_warning ("Can't get the name of geometry");
else if (!priv->names.geometry ||
g_strcmp0 (name, priv->names.geometry)) {
g_free (priv->names.geometry);
priv->names.geometry = g_strdup (name);
XFree (name);
}
}
if (priv->xkb->names->symbols <= 0)
g_warning ("XKB symbols setting is not loaded");
else {
name = XGetAtomName (priv->display, priv->xkb->names->symbols);
if (!name)
g_warning ("Can't get the name of symbols");
else if (!priv->names.symbols ||
g_strcmp0 (name, priv->names.symbols)) {
g_free (priv->names.symbols);
priv->names.symbols = g_strdup (name);
XFree (name);
}
}
return TRUE;
}
/**
* eek_xkb_layout_new:
*
* Create a new #EekXkbLayout.
*/
EekLayout *
eek_xkb_layout_new (Display *display,
GError **error)
{
return (EekLayout *) g_initable_new (EEK_TYPE_XKB_LAYOUT,
NULL,
error,
"display", display,
NULL);
}
/**
* eek_xkb_layout_set_names: (skip)
* @layout: an #EekXkbLayout
* @names: XKB component names
* @error: a #GError
*
* Set the XKB component names to @layout.
* Returns: %TRUE if the component names are successfully set, %FALSE otherwise
*/
gboolean
eek_xkb_layout_set_names (EekXkbLayout *layout,
XkbComponentNamesRec *names,
GError **error)
{
if (g_strcmp0 (names->keycodes, layout->priv->names.keycodes)) {
g_free (layout->priv->names.keycodes);
layout->priv->names.keycodes = g_strdup (names->keycodes);
}
if (g_strcmp0 (names->geometry, layout->priv->names.geometry)) {
g_free (layout->priv->names.geometry);
layout->priv->names.geometry = g_strdup (names->geometry);
}
if (g_strcmp0 (names->symbols, layout->priv->names.symbols)) {
g_free (layout->priv->names.symbols);
layout->priv->names.symbols = g_strdup (names->symbols);
}
return get_keyboard_from_server (layout, error);
}
static gboolean
get_keyboard_from_server (EekXkbLayout *layout,
GError **error)
{
EekXkbLayoutPrivate *priv = layout->priv;
if (priv->xkb) {
XkbFreeKeyboard (priv->xkb, 0, True);
priv->xkb = NULL;
}
if (priv->names.keycodes && priv->names.geometry && priv->names.symbols) {
priv->xkb = XkbGetKeyboardByName (priv->display,
XkbUseCoreKbd,
&priv->names,
0,
XKB_COMPONENT_MASK,
False);
} else {
priv->xkb = XkbGetKeyboard (priv->display,
XKB_COMPONENT_MASK,
XkbUseCoreKbd);
if (!get_names_from_server (layout, error)) {
XkbFreeKeyboard (priv->xkb, 0, True);
priv->xkb = NULL;
}
}
if (priv->xkb == NULL) {
g_set_error (error,
EEK_ERROR,
EEK_ERROR_LAYOUT_ERROR,
"can't get keyboard from server");
g_free (priv->names.keycodes);
priv->names.keycodes = NULL;
g_free (priv->names.geometry);
priv->names.geometry = NULL;
g_free (priv->names.symbols);
priv->names.symbols = NULL;
return FALSE;
}
return TRUE;
}
static guint
find_keycode (EekXkbLayout *layout, gchar *key_name)
{
#define KEYSYM_NAME_MAX_LENGTH 4
guint keycode;
gint i, j;
XkbKeyNamePtr pkey;
XkbKeyAliasPtr palias;
guint is_name_matched;
gchar *src, *dst;
EekXkbLayoutPrivate *priv = layout->priv;
if (!priv->xkb)
return EEK_INVALID_KEYCODE;
pkey = priv->xkb->names->keys + priv->xkb->min_key_code;
for (keycode = priv->xkb->min_key_code;
keycode <= priv->xkb->max_key_code; keycode++) {
is_name_matched = 1;
src = key_name;
dst = pkey->name;
for (i = KEYSYM_NAME_MAX_LENGTH; --i >= 0;) {
if ('\0' == *src)
break;
if (*src++ != *dst++) {
is_name_matched = 0;
break;
}
}
if (is_name_matched)
return keycode;
pkey++;
}
palias = priv->xkb->names->key_aliases;
for (j = priv->xkb->names->num_key_aliases; --j >= 0;) {
is_name_matched = 1;
src = key_name;
dst = palias->alias;
for (i = KEYSYM_NAME_MAX_LENGTH; --i >= 0;) {
if ('\0' == *src)
break;
if (*src++ != *dst++) {
is_name_matched = 0;
break;
}
}
if (is_name_matched) {
keycode = find_keycode (layout, palias->real);
return keycode;
}
palias++;
}
return EEK_INVALID_KEYCODE;
}
static void
setup_scaling (EekXkbLayout *layout,
gdouble width,
gdouble height)
{
EekXkbLayoutPrivate *priv = layout->priv;
g_return_if_fail (priv->xkb);
g_return_if_fail (priv->xkb->geom->width_mm > 0);
g_return_if_fail (priv->xkb->geom->height_mm > 0);
if (width * priv->xkb->geom->height_mm <
height * priv->xkb->geom->width_mm) {
priv->scale_numerator = width;
priv->scale_denominator = priv->xkb->geom->width_mm;
} else {
priv->scale_numerator = height;
priv->scale_denominator = priv->xkb->geom->height_mm;
}
}
static gboolean
initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error)
{
EekXkbLayout *layout = EEK_XKB_LAYOUT (initable);
if (!get_keyboard_from_server (layout, error))
return FALSE;
if (!get_names_from_server (layout, error))
return FALSE;
return TRUE;
}
static void
initable_iface_init (GInitableIface *initable_iface)
{
initable_iface->init = initable_init;
}

View File

@ -1,71 +0,0 @@
/*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#if !defined(__EEK_H_INSIDE__) && !defined(EEK_COMPILATION)
#error "Only <eek/eek-xkb.h> can be included directly."
#endif
#ifndef EEK_XKB_LAYOUT_H
#define EEK_XKB_LAYOUT_H 1
#include <X11/XKBlib.h>
#include "eek-layout.h"
G_BEGIN_DECLS
#define EEK_TYPE_XKB_LAYOUT (eek_xkb_layout_get_type())
#define EEK_XKB_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEK_TYPE_XKB_LAYOUT, EekXkbLayout))
#define EEK_XKB_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEK_TYPE_XKB_LAYOUT, EekXkbLayoutClass))
#define EEK_IS_XKB_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEK_TYPE_XKB_LAYOUT))
#define EEK_IS_XKB_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_XKB_LAYOUT))
#define EEK_XKB_LAYOUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_XKB_LAYOUT, EekXkbLayoutClass))
typedef struct _EekXkbLayout EekXkbLayout;
typedef struct _EekXkbLayoutClass EekXkbLayoutClass;
typedef struct _EekXkbLayoutPrivate EekXkbLayoutPrivate;
struct _EekXkbLayout
{
/*< private >*/
EekLayout parent;
EekXkbLayoutPrivate *priv;
};
struct _EekXkbLayoutClass
{
/*< private >*/
EekLayoutClass parent_class;
/*< private >*/
/* padding */
gpointer pdummy[24];
};
GType eek_xkb_layout_get_type (void) G_GNUC_CONST;
EekLayout *eek_xkb_layout_new (Display *display,
GError **error);
gboolean eek_xkb_layout_set_names (EekXkbLayout *layout,
XkbComponentNamesRec *names,
GError **error);
G_END_DECLS
#endif /* #ifndef EEK_XKB_LAYOUT_H */

View File

@ -1,26 +0,0 @@
/*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#ifndef EEK_XKB_H
#define EEK_XKB_H 1
#include "eek.h"
#include "eek-xkb-layout.h"
#endif /* EEK_XKB_H */

View File

@ -1,30 +0,0 @@
# Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
# Copyright (C) 2010-2011 Red Hat, Inc.
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libeek-xkl
Description: A Library to Create Keyboard-like UI (Libxklavier Support)
URL: http://fedorahosted.org/eekboard/
Version: @VERSION@
Requires: eek-@EEK_API_VERSION@ libxklavier
Libs: -L${libdir} -leek-xkl
Cflags: -I${includedir}/eek-@EEK_API_VERSION@

View File

@ -1,663 +0,0 @@
/*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
/**
* SECTION:eek-xkl-layout
* @short_description: Layout engine using Libxklavier configuration
*
* The #EekXklLayout is a simple wrapper around #EekXkbLayout class
* to use Libxklavier configuration.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include <libxklavier/xklavier.h>
#include <gio/gio.h>
#include <string.h>
#include "eek-xkl-layout.h"
#define noKBDRAW_DEBUG
static GInitableIface *parent_initable_iface;
static void initable_iface_init (GInitableIface *initable_iface);
G_DEFINE_TYPE_WITH_CODE (EekXklLayout, eek_xkl_layout, EEK_TYPE_XKB_LAYOUT,
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
initable_iface_init));
#define EEK_XKL_LAYOUT_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_XKL_LAYOUT, EekXklLayoutPrivate))
enum {
PROP_0,
PROP_MODEL,
PROP_LAYOUTS,
PROP_VARIANTS,
PROP_OPTIONS,
PROP_LAST
};
struct _EekXklLayoutPrivate
{
XklEngine *engine;
XklConfigRec *config;
};
/* from gnome-keyboard-properties-xkbpv.c:
* BAD STYLE: Taken from xklavier_private_xkb.h
* Any ideas on architectural improvements are WELCOME
*/
extern gboolean xkl_xkb_config_native_prepare (XklEngine * engine,
const XklConfigRec * data,
XkbComponentNamesPtr
component_names);
extern void xkl_xkb_config_native_cleanup (XklEngine * engine,
XkbComponentNamesPtr
component_names);
static gboolean set_xkb_component_names (EekXklLayout *layout,
XklConfigRec *config);
static void
eek_xkl_layout_dispose (GObject *object)
{
EekXklLayoutPrivate *priv = EEK_XKL_LAYOUT_GET_PRIVATE (object);
if (priv->config) {
g_object_unref (priv->config);
priv->config = NULL;
}
G_OBJECT_CLASS (eek_xkl_layout_parent_class)->dispose (object);
}
static void
eek_xkl_layout_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
EekXklLayout *layout = EEK_XKL_LAYOUT(object);
switch (prop_id) {
case PROP_MODEL:
eek_xkl_layout_set_model (layout, g_value_get_string (value));
break;
case PROP_LAYOUTS:
eek_xkl_layout_set_layouts (layout, g_value_get_boxed (value));
break;
case PROP_VARIANTS:
eek_xkl_layout_set_variants (layout, g_value_get_boxed (value));
break;
case PROP_OPTIONS:
eek_xkl_layout_set_options (layout, g_value_get_boxed (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
eek_xkl_layout_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
EekXklLayout *layout = EEK_XKL_LAYOUT(object);
switch (prop_id) {
case PROP_MODEL:
g_value_set_string (value,
eek_xkl_layout_get_model (layout));
break;
case PROP_LAYOUTS:
g_value_set_boxed (value,
eek_xkl_layout_get_layouts (layout));
break;
case PROP_VARIANTS:
g_value_set_boxed (value,
eek_xkl_layout_get_variants (layout));
break;
case PROP_OPTIONS:
g_value_set_boxed (value,
eek_xkl_layout_get_options (layout));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
eek_xkl_layout_class_init (EekXklLayoutClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
g_type_class_add_private (gobject_class, sizeof (EekXklLayoutPrivate));
gobject_class->dispose = eek_xkl_layout_dispose;
gobject_class->set_property = eek_xkl_layout_set_property;
gobject_class->get_property = eek_xkl_layout_get_property;
/**
* EekXklLayout:model:
*
* The libxklavier model name of #EekXklLayout.
*/
pspec = g_param_spec_string ("model",
"Model",
"Libxklavier model",
NULL,
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_MODEL, pspec);
/**
* EekXklLayout:layouts:
*
* The libxklavier layout names of #EekXklLayout.
*/
pspec = g_param_spec_boxed ("layouts",
"Layouts",
"Libxklavier layouts",
G_TYPE_STRV,
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_LAYOUTS, pspec);
/**
* EekXklLayout:variants:
*
* The libxklavier variant names of #EekXklLayout.
*/
pspec = g_param_spec_boxed ("variants",
"Variants",
"Libxklavier variants",
G_TYPE_STRV,
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_VARIANTS, pspec);
/**
* EekXklLayout:options:
*
* The libxklavier option names of #EekXklLayout.
*/
pspec = g_param_spec_boxed ("options",
"Options",
"Libxklavier options",
G_TYPE_STRV,
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_OPTIONS, pspec);
}
static void
eek_xkl_layout_init (EekXklLayout *self)
{
self->priv = EEK_XKL_LAYOUT_GET_PRIVATE (self);
}
/**
* eek_xkl_layout_new:
*
* Create a new #EekXklLayout.
*/
EekLayout *
eek_xkl_layout_new (Display *display, GError **error)
{
return (EekLayout *) g_initable_new (EEK_TYPE_XKL_LAYOUT,
NULL,
error,
"display", display,
NULL);
}
G_INLINE_FUNC void
merge_xkl_config_rec (XklConfigRec *dst, XklConfigRec *src)
{
if (src->model) {
g_free (dst->model);
dst->model = g_strdup (src->model);
}
if (src->layouts) {
g_strfreev (dst->layouts);
dst->layouts = g_strdupv (src->layouts);
}
if (src->variants) {
g_strfreev (dst->variants);
dst->variants = g_strdupv (src->variants);
}
if (src->options) {
g_strfreev (dst->options);
dst->options = g_strdupv (src->options);
}
}
/**
* eek_xkl_layout_set_config: (skip)
* @layout: an #EekXklLayout
* @config: Libxklavier configuration
*
* Reconfigure @layout with @config.
* Returns: %TRUE if the current layout changed, %FALSE otherwise
*/
gboolean
eek_xkl_layout_set_config (EekXklLayout *layout,
XklConfigRec *config)
{
EekXklLayoutPrivate *priv = EEK_XKL_LAYOUT_GET_PRIVATE (layout);
XklConfigRec *c;
gboolean retval;
g_return_val_if_fail (priv, FALSE);
c = xkl_config_rec_new ();
merge_xkl_config_rec (c, priv->config);
merge_xkl_config_rec (c, config);
retval = set_xkb_component_names (layout, c);
g_object_unref (c);
merge_xkl_config_rec (priv->config, config);
return retval;
}
/**
* eek_xkl_layout_set_config_full:
* @layout: an #EekXklLayout
* @model: Libxklavier model name
* @layouts: Libxklavier layouts
* @variants: Libxklavier variants
* @options: Libxklavier options
*
* Reconfigure @layout with @model, @layouts, @variants, and @options.
* This function is merely a wrapper around
* eek_xkl_layout_set_config() to avoid passing a pointer of
* XklConfigRec, which is not currently available in the
* gobject-introspection repository.
*
* Returns: %TRUE if the current layout changed, %FALSE otherwise
* Since: 0.0.2
*/
gboolean
eek_xkl_layout_set_config_full (EekXklLayout *layout,
gchar *model,
gchar **layouts,
gchar **variants,
gchar **options)
{
XklConfigRec *config;
gboolean retval;
config = xkl_config_rec_new ();
config->model = g_strdup (model);
config->layouts = g_strdupv (layouts);
config->variants = g_strdupv (variants);
config->options = g_strdupv (options);
retval = eek_xkl_layout_set_config (layout, config);
g_object_unref (config);
return retval;
}
/**
* eek_xkl_layout_set_model:
* @layout: an #EekXklLayout
* @model: model name
*
* Set the model name of @layout configuration (in the Libxklavier terminology).
* Returns: %TRUE if the current layout changed, %FALSE otherwise
*/
gboolean
eek_xkl_layout_set_model (EekXklLayout *layout,
const gchar *model)
{
EekXklLayoutPrivate *priv = EEK_XKL_LAYOUT_GET_PRIVATE (layout);
XklConfigRec *config;
gboolean retval;
g_return_val_if_fail (priv, FALSE);
config = xkl_config_rec_new ();
/* config->model will be freed on g_object_unref (config) */
if (model)
config->model = g_strdup (model);
else
config->model = NULL;
retval = eek_xkl_layout_set_config (layout, config);
g_object_unref (config);
return retval;
}
/**
* eek_xkl_layout_set_layouts:
* @layout: an #EekXklLayout
* @layouts: layout names
*
* Set the layout names of @layout (in the Libxklavier terminology).
* Returns: %TRUE if the current layout changed, %FALSE otherwise
*/
gboolean
eek_xkl_layout_set_layouts (EekXklLayout *layout,
gchar **layouts)
{
EekXklLayoutPrivate *priv = EEK_XKL_LAYOUT_GET_PRIVATE (layout);
XklConfigRec *config;
gboolean retval;
g_return_val_if_fail (priv, FALSE);
config = xkl_config_rec_new ();
/* config->layouts will be freed on g_object_unref (config) */
if (layouts)
config->layouts = g_strdupv (layouts);
else
config->layouts = layouts;
retval = eek_xkl_layout_set_config (layout, config);
g_object_unref (config);
return retval;
}
/**
* eek_xkl_layout_set_variants:
* @layout: an #EekXklLayout
* @variants: variant names
*
* Set the variant names of @layout (in the Libxklavier terminology).
* Returns: %TRUE if the current layout changed, %FALSE otherwise
*/
gboolean
eek_xkl_layout_set_variants (EekXklLayout *layout,
gchar **variants)
{
EekXklLayoutPrivate *priv = EEK_XKL_LAYOUT_GET_PRIVATE (layout);
XklConfigRec *config;
gboolean retval;
g_return_val_if_fail (priv, FALSE);
config = xkl_config_rec_new ();
/* config->variants will be freed on g_object_unref (config) */
if (variants)
config->variants = g_strdupv (variants);
else
config->variants = NULL;
retval = eek_xkl_layout_set_config (layout, config);
g_object_unref (config);
return retval;
}
/**
* eek_xkl_layout_set_options:
* @layout: an #EekXklLayout
* @options: option names
*
* Set the option names of @layout (in the Libxklavier terminology).
* Returns: %TRUE if the current layout changed, %FALSE otherwise
*/
gboolean
eek_xkl_layout_set_options (EekXklLayout *layout,
gchar **options)
{
EekXklLayoutPrivate *priv = EEK_XKL_LAYOUT_GET_PRIVATE (layout);
XklConfigRec *config;
gboolean retval;
g_return_val_if_fail (priv, FALSE);
config = xkl_config_rec_new ();
/* config->options will be freed on g_object_unref (config) */
if (options)
config->options = options;
else
config->options = NULL;
retval = eek_xkl_layout_set_config (layout, config);
g_object_unref (config);
return retval;
}
/**
* eek_xkl_layout_enable_option:
* @layout: an #EekXklLayout
* @option: option name
*
* Set the option of @layout (in the Libxklavier terminology).
* Returns: %TRUE if the current layout changed, %FALSE otherwise
*/
gboolean
eek_xkl_layout_enable_option (EekXklLayout *layout,
const gchar *option)
{
gchar **options, **_options;
gint i, j;
options = eek_xkl_layout_get_options (layout);
for (i = 0; options && options[i]; i++)
if (g_strcmp0 (options[i], option) == 0)
return TRUE;
_options = g_new0 (gchar *, (i + 2));
for (j = 0; j < i; j++)
_options[j] = g_strdup (options[j]);
_options[i] = g_strdup (option);
/* eek_xkl_layout_set_options() will free _options and its elements. */
return eek_xkl_layout_set_options (layout, _options);
}
/**
* eek_xkl_layout_disable_option:
* @layout: an #EekXklLayout
* @option: option name
*
* Unset the option of @layout (in the Libxklavier terminology).
* Returns: %TRUE if the current layout changed, %FALSE otherwise
*/
gboolean
eek_xkl_layout_disable_option (EekXklLayout *layout,
const gchar *option)
{
gchar **options, **_options;
gint i, j, k;
options = eek_xkl_layout_get_options (layout);
if (!options)
return TRUE;
for (i = 0, k = 0; options[i]; i++)
if (g_strcmp0 (options[i], option) == 0)
k = i;
if (options[k] == NULL)
return TRUE;
_options = g_new0 (gchar *, i);
for (j = 0; j < k; j++)
_options[j] = g_strdup (options[j]);
for (j = k + 1; j < i; j++)
_options[j] = g_strdup (options[j]);
/* eek_xkl_layout_set_options() will free _options and its elements. */
return eek_xkl_layout_set_options (layout, _options);
}
/**
* eek_xkl_layout_get_model:
* @layout: an #EekXklLayout
*
* Get the model name of @layout configuration (in the Libxklavier terminology).
*/
gchar *
eek_xkl_layout_get_model (EekXklLayout *layout)
{
EekXklLayoutPrivate *priv = EEK_XKL_LAYOUT_GET_PRIVATE (layout);
g_return_val_if_fail (priv, NULL);
return g_strdup (priv->config->model);
}
/**
* eek_xkl_layout_get_layouts:
* @layout: an #EekXklLayout
*
* Get the layout names of @layout configuration (in the Libxklavier
* terminology).
*/
gchar **
eek_xkl_layout_get_layouts (EekXklLayout *layout)
{
EekXklLayoutPrivate *priv = EEK_XKL_LAYOUT_GET_PRIVATE (layout);
g_return_val_if_fail (priv, NULL);
return g_strdupv (priv->config->layouts);
}
/**
* eek_xkl_layout_get_variants:
* @layout: an #EekXklLayout
*
* Get the variant names of @layout configuration (in the Libxklavier
* terminology).
*/
gchar **
eek_xkl_layout_get_variants (EekXklLayout *layout)
{
EekXklLayoutPrivate *priv = EEK_XKL_LAYOUT_GET_PRIVATE (layout);
g_return_val_if_fail (priv, NULL);
return g_strdupv (priv->config->variants);
}
/**
* eek_xkl_layout_get_options:
* @layout: an #EekXklLayout
*
* Get the option names of @layout configuration (in the Libxklavier
* terminology).
*/
gchar **
eek_xkl_layout_get_options (EekXklLayout *layout)
{
EekXklLayoutPrivate *priv = EEK_XKL_LAYOUT_GET_PRIVATE (layout);
g_return_val_if_fail (priv, NULL);
return g_strdupv (priv->config->options);
}
static gboolean
set_xkb_component_names (EekXklLayout *layout, XklConfigRec *config)
{
EekXklLayoutPrivate *priv = layout->priv;
XkbComponentNamesRec names;
gboolean retval = FALSE;
#if DEBUG
if (config->layouts) {
gint i;
fprintf (stderr, "layout = ");
for (i = 0; config->layouts[i] != NULL; i++)
fprintf (stderr, "\"%s\" ", config->layouts[i]);
fputc ('\n', stderr);
} else
fprintf (stderr, "layouts = NULL\n");
if (config->variants) {
gint i;
fprintf (stderr, "variant = ");
for (i = 0; config->variants[i]; i++)
fprintf (stderr, "\"%s\" ", config->variants[i]);
fputc ('\n', stderr);
} else
fprintf (stderr, "variants = NULL\n");
if (config->options) {
gint i;
fprintf (stderr, "option = ");
for (i = 0; config->options[i]; i++)
fprintf (stderr, "\"%s\" ", config->options[i]);
fputc ('\n', stderr);
} else
fprintf (stderr, "options = NULL\n");
#endif
if (xkl_xkb_config_native_prepare (priv->engine, config, &names)) {
GError *error = NULL;
retval = eek_xkb_layout_set_names (EEK_XKB_LAYOUT(layout),
&names,
&error);
if (!retval)
g_warning ("can't set XKB layout");
xkl_xkb_config_native_cleanup (priv->engine, &names);
}
return retval;
}
/**
* eek_xkl_layout_get_option:
* @layout: an #EekXklLayout
* @option: option name
*
* Tell if the option of @layout (in the Libxklavier terminology) is set.
* Returns: %TRUE if the option is set, %FALSE otherwise
*/
gboolean
eek_xkl_layout_get_option (EekXklLayout *layout,
const gchar *option)
{
gchar **options;
gint i;
options = eek_xkl_layout_get_options (layout);
for (i = 0; options && options[i]; i++)
if (g_strcmp0 (options[i], option) == 0)
return TRUE;
return FALSE;
}
static gboolean
initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error)
{
EekXklLayout *layout = EEK_XKL_LAYOUT (initable);
Display *display;
if (!parent_initable_iface->init (initable, cancellable, error))
return FALSE;
layout->priv->config = xkl_config_rec_new ();
g_object_get (G_OBJECT (initable),
"display", &display,
NULL);
layout->priv->engine = xkl_engine_get_instance (display);
if (!xkl_config_rec_get_from_server (layout->priv->config,
layout->priv->engine)) {
g_set_error (error,
EEK_ERROR,
EEK_ERROR_LAYOUT_ERROR,
"can't load libxklavier configuration");
return FALSE;
}
set_xkb_component_names (layout, layout->priv->config);
return TRUE;
}
static void
initable_iface_init (GInitableIface *initable_iface)
{
parent_initable_iface = g_type_interface_peek_parent (initable_iface);
initable_iface->init = initable_init;
}

View File

@ -1,97 +0,0 @@
/*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#if !defined(__EEK_H_INSIDE__) && !defined(EEK_COMPILATION)
#error "Only <eek/eek-xkl.h> can be included directly."
#endif
#ifndef EEK_XKL_LAYOUT_H
#define EEK_XKL_LAYOUT_H 1
#include <libxklavier/xklavier.h>
#include "eek-xkb-layout.h"
G_BEGIN_DECLS
#define EEK_TYPE_XKL_LAYOUT (eek_xkl_layout_get_type())
#define EEK_XKL_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEK_TYPE_XKL_LAYOUT, EekXklLayout))
#define EEK_XKL_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEK_TYPE_XKL_LAYOUT, EekXklLayoutClass))
#define EEK_IS_XKL_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEK_TYPE_XKL_LAYOUT))
#define EEK_IS_XKL_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_XKL_LAYOUT))
#define EEK_XKL_LAYOUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_XKL_LAYOUT, EekXklLayoutClass))
typedef struct _EekXklLayout EekXklLayout;
typedef struct _EekXklLayoutClass EekXklLayoutClass;
typedef struct _EekXklLayoutPrivate EekXklLayoutPrivate;
struct _EekXklLayout
{
/*< private >*/
EekXkbLayout parent;
EekXklLayoutPrivate *priv;
};
struct _EekXklLayoutClass
{
/*< private >*/
EekXkbLayoutClass parent_class;
/*< private >*/
/* padding */
gpointer pdummy[24];
};
GType eek_xkl_layout_get_type (void) G_GNUC_CONST;
EekLayout *eek_xkl_layout_new (Display *display,
GError **error);
gboolean eek_xkl_layout_set_config (EekXklLayout *layout,
XklConfigRec *config);
gboolean eek_xkl_layout_set_config_full (EekXklLayout *layout,
gchar *model,
gchar **layouts,
gchar **variants,
gchar **options);
gboolean eek_xkl_layout_set_model (EekXklLayout *layout,
const gchar *model);
gboolean eek_xkl_layout_set_layouts (EekXklLayout *layout,
gchar **layouts);
gboolean eek_xkl_layout_set_variants (EekXklLayout *layout,
gchar **variants);
gboolean eek_xkl_layout_set_options (EekXklLayout *layout,
gchar **options);
gboolean eek_xkl_layout_enable_option (EekXklLayout *layout,
const gchar *option);
gboolean eek_xkl_layout_disable_option (EekXklLayout *layout,
const gchar *option);
gchar *eek_xkl_layout_get_model (EekXklLayout *layout);
gchar **eek_xkl_layout_get_layouts (EekXklLayout *layout);
gchar **eek_xkl_layout_get_variants (EekXklLayout *layout);
gchar **eek_xkl_layout_get_options (EekXklLayout *layout);
gboolean eek_xkl_layout_get_option (EekXklLayout *layout,
const gchar *option);
G_END_DECLS
#endif /* #ifndef EEK_XKL_LAYOUT_H */

View File

@ -1,26 +0,0 @@
/*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#ifndef EEK_XKL_H
#define EEK_XKL_H 1
#include "eek.h"
#include "eek-xkl-layout.h"
#endif /* EEK_XKL_H */

View File

@ -1,7 +1,7 @@
/* /*
* Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org> * Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2011 Red Hat, Inc. * Copyright (C) 2011 Red Hat, Inc.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
@ -21,10 +21,9 @@
* @short_description: Layout engine which loads layout information from XML * @short_description: Layout engine which loads layout information from XML
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */
#include <gio/gio.h> /* GResource */
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -35,6 +34,8 @@
#include "eek-keysym.h" #include "eek-keysym.h"
#include "eek-text.h" #include "eek-text.h"
#include "squeekboard-resources.h"
enum { enum {
PROP_0, PROP_0,
PROP_ID, PROP_ID,
@ -43,19 +44,18 @@ enum {
static void initable_iface_init (GInitableIface *initable_iface); static void initable_iface_init (GInitableIface *initable_iface);
G_DEFINE_TYPE_WITH_CODE (EekXmlLayout, eek_xml_layout, EEK_TYPE_LAYOUT, typedef struct _EekXmlLayoutPrivate
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
initable_iface_init));
#define EEK_XML_LAYOUT_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_XML_LAYOUT, EekXmlLayoutPrivate))
struct _EekXmlLayoutPrivate
{ {
gchar *id; gchar *id;
gchar *keyboards_dir; gchar *keyboards_dir;
EekXmlKeyboardDesc *desc; EekXmlKeyboardDesc *desc;
}; } EekXmlLayoutPrivate;
G_DEFINE_TYPE_EXTENDED (EekXmlLayout, eek_xml_layout, EEK_TYPE_LAYOUT,
0, /* GTypeFlags */
G_ADD_PRIVATE(EekXmlLayout)
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
initable_iface_init))
G_DEFINE_BOXED_TYPE(EekXmlKeyboardDesc, eek_xml_keyboard_desc, eek_xml_keyboard_desc_copy, eek_xml_keyboard_desc_free); G_DEFINE_BOXED_TYPE(EekXmlKeyboardDesc, eek_xml_keyboard_desc, eek_xml_keyboard_desc_copy, eek_xml_keyboard_desc_free);
@ -79,10 +79,6 @@ static gboolean parse_symbols (const gchar *path,
EekKeyboard *keyboard, EekKeyboard *keyboard,
GError **error); GError **error);
static void scale_keyboard (EekKeyboard *keyboard,
gdouble width,
gdouble height);
static gboolean validate (const gchar **valid_path_list, static gboolean validate (const gchar **valid_path_list,
gsize valid_path_list_len, gsize valid_path_list_len,
const gchar *element_name, const gchar *element_name,
@ -247,6 +243,7 @@ struct _GeometryParseData {
gchar *name; gchar *name;
EekOutline outline; EekOutline outline;
gchar *oref; gchar *oref;
gint keycode;
GHashTable *key_oref_hash; GHashTable *key_oref_hash;
GHashTable *oref_outline_hash; GHashTable *oref_outline_hash;
@ -269,6 +266,7 @@ geometry_parse_data_new (EekKeyboard *keyboard)
g_str_equal, g_str_equal,
g_free, g_free,
(GDestroyNotify)eek_outline_free); (GDestroyNotify)eek_outline_free);
data->keycode = 8;
return data; return data;
} }
@ -360,8 +358,6 @@ geometry_start_element_callback (GMarkupParseContext *pcontext,
if (g_strcmp0 (data->element_stack->data, "geometry") == 0) if (g_strcmp0 (data->element_stack->data, "geometry") == 0)
eek_element_set_bounds (EEK_ELEMENT(data->keyboard), &bounds); eek_element_set_bounds (EEK_ELEMENT(data->keyboard), &bounds);
else if (g_strcmp0 (data->element_stack->data, "section") == 0)
eek_element_set_bounds (EEK_ELEMENT(data->section), &bounds);
goto out; goto out;
} }
@ -399,26 +395,29 @@ geometry_start_element_callback (GMarkupParseContext *pcontext,
guint keycode; guint keycode;
attribute = get_attribute (attribute_names, attribute_values, attribute = get_attribute (attribute_names, attribute_values,
"keycode"); "name");
if (attribute == NULL) { if (attribute == NULL) {
g_set_error (error, g_set_error (error,
G_MARKUP_ERROR, G_MARKUP_ERROR,
G_MARKUP_ERROR_MISSING_ATTRIBUTE, G_MARKUP_ERROR_MISSING_ATTRIBUTE,
"no \"keycode\" attribute for \"key\""); "no \"name\" attribute for \"key\"");
return; return;
} }
keycode = strtoul (attribute, NULL, 10); gchar *name = g_strdup (attribute);
attribute = get_attribute (attribute_names, attribute_values,
"keycode");
if (attribute != NULL)
keycode = strtol (attribute, NULL, 10);
else
keycode = data->keycode++;
data->key = eek_section_create_key (data->section, data->key = eek_section_create_key (data->section,
name,
keycode, keycode,
data->num_columns, data->num_columns,
data->num_rows - 1); data->num_rows - 1);
attribute = get_attribute (attribute_names, attribute_values,
"name");
if (attribute != NULL)
eek_element_set_name (EEK_ELEMENT(data->key), attribute);
attribute = get_attribute (attribute_names, attribute_values, attribute = get_attribute (attribute_names, attribute_values,
"oref"); "oref");
if (attribute == NULL) { if (attribute == NULL) {
@ -452,7 +451,7 @@ geometry_start_element_callback (GMarkupParseContext *pcontext,
"corner-radius"); "corner-radius");
if (attribute != NULL) if (attribute != NULL)
data->corner_radius = g_strtod (attribute, NULL); data->corner_radius = g_strtod (attribute, NULL);
goto out; goto out;
} }
@ -622,28 +621,25 @@ symbols_start_element_callback (GMarkupParseContext *pcontext,
return; return;
if (g_strcmp0 (element_name, "key") == 0) { if (g_strcmp0 (element_name, "key") == 0) {
guint keycode;
attribute = get_attribute (attribute_names, attribute_values, attribute = get_attribute (attribute_names, attribute_values,
"keycode"); "name");
if (attribute == NULL) { if (attribute == NULL) {
g_set_error (error, g_set_error (error,
G_MARKUP_ERROR, G_MARKUP_ERROR,
G_MARKUP_ERROR_MISSING_ATTRIBUTE, G_MARKUP_ERROR_MISSING_ATTRIBUTE,
"no \"keycode\" attribute for \"key\""); "no \"name\" attribute for \"key\"");
return; return;
} }
keycode = strtoul (attribute, NULL, 10);
data->key = eek_keyboard_find_key_by_keycode (data->keyboard, data->key = eek_keyboard_find_key_by_name (data->keyboard,
keycode); attribute);
/*if (data->key == NULL) { if (data->key == NULL) {
g_set_error (error, g_set_error (error,
G_MARKUP_ERROR, G_MARKUP_ERROR,
G_MARKUP_ERROR_INVALID_CONTENT, G_MARKUP_ERROR_INVALID_CONTENT,
"no such keycode %u", keycode); "no such key %s", attribute);
return; }
}*/
attribute = get_attribute (attribute_names, attribute_values, attribute = get_attribute (attribute_names, attribute_values,
"groups"); "groups");
@ -726,7 +722,6 @@ symbols_end_element_callback (GMarkupParseContext *pcontext,
gint levels = num_symbols / data->groups; gint levels = num_symbols / data->groups;
EekSymbolMatrix *matrix = eek_symbol_matrix_new (data->groups, EekSymbolMatrix *matrix = eek_symbol_matrix_new (data->groups,
levels); levels);
head = data->symbols = g_slist_reverse (data->symbols); head = data->symbols = g_slist_reverse (data->symbols);
for (i = 0; i < num_symbols; i++) { for (i = 0; i < num_symbols; i++) {
if (head && head->data) { if (head && head->data) {
@ -903,6 +898,7 @@ eek_xml_layout_real_create_keyboard (EekboardContextService *manager,
gdouble initial_height) gdouble initial_height)
{ {
EekXmlLayout *layout = EEK_XML_LAYOUT (self); EekXmlLayout *layout = EEK_XML_LAYOUT (self);
EekXmlLayoutPrivate *priv = eek_xml_layout_get_instance_private (layout);
gboolean retval; gboolean retval;
/* Create an empty keyboard to which geometry and symbols /* Create an empty keyboard to which geometry and symbols
@ -911,8 +907,8 @@ eek_xml_layout_real_create_keyboard (EekboardContextService *manager,
keyboard->manager = manager; keyboard->manager = manager;
/* Read geometry information. */ /* Read geometry information. */
gchar *filename = g_strdup_printf ("%s.xml", layout->priv->desc->geometry); gchar *filename = g_strdup_printf ("%s.xml", priv->desc->geometry);
gchar *path = g_build_filename (layout->priv->keyboards_dir, "geometry", filename, NULL); gchar *path = g_build_filename (priv->keyboards_dir, "geometry", filename, NULL);
g_free (filename); g_free (filename);
GError *error = NULL; GError *error = NULL;
@ -921,7 +917,7 @@ eek_xml_layout_real_create_keyboard (EekboardContextService *manager,
if (!retval) { if (!retval) {
g_object_unref (keyboard); g_object_unref (keyboard);
g_warning ("can't parse geometry file %s: %s", g_warning ("can't parse geometry file %s: %s",
layout->priv->desc->geometry, priv->desc->geometry,
error->message); error->message);
g_error_free (error); g_error_free (error);
return NULL; return NULL;
@ -929,8 +925,8 @@ eek_xml_layout_real_create_keyboard (EekboardContextService *manager,
/* Read symbols information. */ /* Read symbols information. */
GList *loaded = NULL; GList *loaded = NULL;
retval = parse_symbols_with_prerequisites (layout->priv->keyboards_dir, retval = parse_symbols_with_prerequisites (priv->keyboards_dir,
layout->priv->desc->symbols, priv->desc->symbols,
keyboard, keyboard,
&loaded, &loaded,
&error); &error);
@ -938,14 +934,13 @@ eek_xml_layout_real_create_keyboard (EekboardContextService *manager,
if (!retval) { if (!retval) {
g_object_unref (keyboard); g_object_unref (keyboard);
g_warning ("can't parse symbols file %s: %s", g_warning ("can't parse symbols file %s: %s",
layout->priv->desc->symbols, priv->desc->symbols,
error->message); error->message);
g_error_free (error); g_error_free (error);
return NULL; return NULL;
} }
/* Fit keyboard in the given width and hight. */ eek_layout_place_sections(keyboard);
scale_keyboard (keyboard, initial_width, initial_height);
/* Use pre-defined modifier mask here. */ /* Use pre-defined modifier mask here. */
eek_keyboard_set_num_lock_mask (keyboard, EEK_MOD2_MASK); eek_keyboard_set_num_lock_mask (keyboard, EEK_MOD2_MASK);
@ -961,10 +956,12 @@ eek_xml_layout_set_property (GObject *object,
GParamSpec *pspec) GParamSpec *pspec)
{ {
EekXmlLayout *layout = EEK_XML_LAYOUT (object); EekXmlLayout *layout = EEK_XML_LAYOUT (object);
EekXmlLayoutPrivate *priv = eek_xml_layout_get_instance_private (layout);
switch (prop_id) { switch (prop_id) {
case PROP_ID: case PROP_ID:
g_free (layout->priv->id); g_free (priv->id);
layout->priv->id = g_value_dup_string (value); priv->id = g_value_dup_string (value);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -979,9 +976,11 @@ eek_xml_layout_get_property (GObject *object,
GParamSpec *pspec) GParamSpec *pspec)
{ {
EekXmlLayout *layout = EEK_XML_LAYOUT (object); EekXmlLayout *layout = EEK_XML_LAYOUT (object);
EekXmlLayoutPrivate *priv = eek_xml_layout_get_instance_private (layout);
switch (prop_id) { switch (prop_id) {
case PROP_ID: case PROP_ID:
g_value_set_string (value, layout->priv->id); g_value_set_string (value, priv->id);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -992,7 +991,8 @@ eek_xml_layout_get_property (GObject *object,
static void static void
eek_xml_layout_finalize (GObject *object) eek_xml_layout_finalize (GObject *object)
{ {
EekXmlLayoutPrivate *priv = EEK_XML_LAYOUT_GET_PRIVATE (object); EekXmlLayoutPrivate *priv = eek_xml_layout_get_instance_private (
EEK_XML_LAYOUT (object));
g_free (priv->id); g_free (priv->id);
@ -1011,8 +1011,6 @@ eek_xml_layout_class_init (EekXmlLayoutClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec; GParamSpec *pspec;
g_type_class_add_private (gobject_class, sizeof (EekXmlLayoutPrivate));
layout_class->create_keyboard = eek_xml_layout_real_create_keyboard; layout_class->create_keyboard = eek_xml_layout_real_create_keyboard;
gobject_class->set_property = eek_xml_layout_set_property; gobject_class->set_property = eek_xml_layout_set_property;
@ -1031,7 +1029,7 @@ eek_xml_layout_class_init (EekXmlLayoutClass *klass)
static void static void
eek_xml_layout_init (EekXmlLayout *self) eek_xml_layout_init (EekXmlLayout *self)
{ {
self->priv = EEK_XML_LAYOUT_GET_PRIVATE (self); /* void */
} }
EekLayout * EekLayout *
@ -1050,16 +1048,17 @@ initable_init (GInitable *initable,
GError **error) GError **error)
{ {
EekXmlLayout *layout = EEK_XML_LAYOUT (initable); EekXmlLayout *layout = EEK_XML_LAYOUT (initable);
EekXmlLayoutPrivate *priv = eek_xml_layout_get_instance_private (layout);
GList *keyboards, *p; GList *keyboards, *p;
gchar *path; gchar *path;
EekXmlKeyboardDesc *desc; EekXmlKeyboardDesc *desc;
layout->priv->keyboards_dir = (gchar *) g_getenv ("EEKBOARD_KEYBOARDSDIR"); priv->keyboards_dir = g_strdup ((gchar *) g_getenv ("EEKBOARD_KEYBOARDSDIR"));
if (layout->priv->keyboards_dir == NULL)
layout->priv->keyboards_dir = KEYBOARDSDIR;
layout->priv->keyboards_dir = g_strdup (layout->priv->keyboards_dir);
path = g_build_filename (layout->priv->keyboards_dir, "keyboards.xml", NULL); if (priv->keyboards_dir == NULL)
priv->keyboards_dir = g_strdup ("resource:///sm/puri/squeekboard/keyboards/");
path = g_build_filename (priv->keyboards_dir, "keyboards.xml", NULL);
keyboards = parse_keyboards (path, error); keyboards = parse_keyboards (path, error);
g_free (path); g_free (path);
if (error && *error) if (error && *error)
@ -1067,7 +1066,7 @@ initable_init (GInitable *initable,
for (p = keyboards; p; p = p->next) { for (p = keyboards; p; p = p->next) {
desc = p->data; desc = p->data;
if (g_strcmp0 (desc->id, layout->priv->id) == 0) if (g_strcmp0 (desc->id, priv->id) == 0)
break; break;
} }
if (p == NULL) { if (p == NULL) {
@ -1075,12 +1074,12 @@ initable_init (GInitable *initable,
EEK_ERROR, EEK_ERROR,
EEK_ERROR_LAYOUT_ERROR, EEK_ERROR_LAYOUT_ERROR,
"no such keyboard %s", "no such keyboard %s",
layout->priv->id); priv->id);
return FALSE; return FALSE;
} }
keyboards = g_list_remove_link (keyboards, p); keyboards = g_list_remove_link (keyboards, p);
layout->priv->desc = p->data; priv->desc = p->data;
g_list_free_1 (p); g_list_free_1 (p);
g_list_free_full (keyboards, (GDestroyNotify) keyboard_desc_free); g_list_free_full (keyboards, (GDestroyNotify) keyboard_desc_free);
@ -1108,7 +1107,7 @@ eek_xml_list_keyboards (void)
keyboards_dir = g_getenv ("EEKBOARD_KEYBOARDSDIR"); keyboards_dir = g_getenv ("EEKBOARD_KEYBOARDSDIR");
if (keyboards_dir == NULL) if (keyboards_dir == NULL)
keyboards_dir = KEYBOARDSDIR; keyboards_dir = g_strdup ("resource:///sm/puri/squeekboard/keyboards/");
path = g_build_filename (keyboards_dir, "keyboards.xml", NULL); path = g_build_filename (keyboards_dir, "keyboards.xml", NULL);
keyboards = parse_keyboards (path, NULL); keyboards = parse_keyboards (path, NULL);
g_free (path); g_free (path);
@ -1133,38 +1132,6 @@ eek_xml_keyboard_desc_free (EekXmlKeyboardDesc *desc)
g_slice_free (EekXmlKeyboardDesc, desc); g_slice_free (EekXmlKeyboardDesc, desc);
} }
struct place_data {
double desired_width;
double current_offset;
EekKeyboard *keyboard;
};
const double section_spacing = 7.0;
static void section_placer(EekElement *element, gpointer user_data) {
struct place_data *data = (struct place_data*)user_data;
EekBounds section_bounds = {0};
eek_element_get_bounds(element, &section_bounds);
section_bounds.width = data->desired_width;
eek_element_set_bounds(element, &section_bounds);
// Sections are rows now. Gather up all the keys and adjust their bounds.
eek_section_place_keys(EEK_SECTION(element), EEK_KEYBOARD(data->keyboard));
eek_element_get_bounds(element, &section_bounds);
section_bounds.y = data->current_offset;
eek_element_set_bounds(element, &section_bounds);
data->current_offset += section_bounds.height + section_spacing;
}
static void section_counter(EekElement *element, gpointer user_data) {
double *total_height = user_data;
EekBounds section_bounds = {0};
eek_element_get_bounds(element, &section_bounds);
*total_height += section_bounds.height + section_spacing;
}
static gboolean static gboolean
parse_geometry (const gchar *path, EekKeyboard *keyboard, GError **error) parse_geometry (const gchar *path, EekKeyboard *keyboard, GError **error)
{ {
@ -1177,7 +1144,9 @@ parse_geometry (const gchar *path, EekKeyboard *keyboard, GError **error)
GFileInputStream *input; GFileInputStream *input;
gboolean retval; gboolean retval;
file = g_file_new_for_path (path); file = g_str_has_prefix (path, "resource://")
? g_file_new_for_uri (path)
: g_file_new_for_path (path);
input = g_file_read (file, NULL, error); input = g_file_read (file, NULL, error);
g_object_unref (file); g_object_unref (file);
@ -1217,27 +1186,6 @@ parse_geometry (const gchar *path, EekKeyboard *keyboard, GError **error)
} }
g_hash_table_destroy (oref_hash); g_hash_table_destroy (oref_hash);
/* Order rows */
// This needs to be done after outlines, because outlines define key sizes
// TODO: do this only for rows without bounds
// The keyboard width is given by the user via screen size. The height will be given dynamically.
// TODO: calculate max line width beforehand for button centering. Leave keyboard centering to the renderer later
EekBounds keyboard_bounds = {0};
eek_element_get_bounds(EEK_ELEMENT(keyboard), &keyboard_bounds);
struct place_data placer_data = {
.desired_width = keyboard_bounds.width,
.current_offset = 0,
.keyboard = keyboard,
};
eek_container_foreach_child(EEK_CONTAINER(keyboard), section_placer, &placer_data);
double total_height = 0;
eek_container_foreach_child(EEK_CONTAINER(keyboard), section_counter, &total_height);
keyboard_bounds.height = total_height;
eek_element_set_bounds(EEK_ELEMENT(keyboard), &keyboard_bounds);
geometry_parse_data_free (data); geometry_parse_data_free (data);
return TRUE; return TRUE;
} }
@ -1303,7 +1251,9 @@ parse_symbols (const gchar *path, EekKeyboard *keyboard, GError **error)
GFileInputStream *input; GFileInputStream *input;
gboolean retval; gboolean retval;
file = g_file_new_for_path (path); file = g_str_has_prefix (path, "resource://")
? g_file_new_for_uri (path)
: g_file_new_for_path (path);
input = g_file_read (file, NULL, error); input = g_file_read (file, NULL, error);
g_object_unref (file); g_object_unref (file);
@ -1336,7 +1286,9 @@ parse_prerequisites (const gchar *path, GError **error)
GList *prerequisites; GList *prerequisites;
gboolean retval; gboolean retval;
file = g_file_new_for_path (path); file = g_str_has_prefix (path, "resource://")
? g_file_new_for_uri (path)
: g_file_new_for_path (path);
input = g_file_read (file, NULL, error); input = g_file_read (file, NULL, error);
g_object_unref (file); g_object_unref (file);
@ -1371,7 +1323,9 @@ parse_keyboards (const gchar *path, GError **error)
GList *keyboards; GList *keyboards;
gboolean retval; gboolean retval;
file = g_file_new_for_path (path); file = g_str_has_prefix (path, "resource://")
? g_file_new_for_uri (path)
: g_file_new_for_path (path);
input = g_file_read (file, NULL, error); input = g_file_read (file, NULL, error);
g_object_unref (file); g_object_unref (file);
@ -1397,65 +1351,6 @@ parse_keyboards (const gchar *path, GError **error)
return keyboards; return keyboards;
} }
static void scale_bounds_callback (EekElement *element,
gpointer user_data);
static void
scale_bounds (EekElement *element,
gdouble scale)
{
EekBounds bounds;
eek_element_get_bounds (element, &bounds);
bounds.x *= scale;
bounds.y *= scale;
bounds.width *= scale;
bounds.height *= scale;
eek_element_set_bounds (element, &bounds);
if (EEK_IS_CONTAINER(element))
eek_container_foreach_child (EEK_CONTAINER(element),
scale_bounds_callback,
&scale);
}
static void
scale_bounds_callback (EekElement *element,
gpointer user_data)
{
scale_bounds (element, *(gdouble *)user_data);
}
static void scale_keyboard (EekKeyboard *keyboard,
gdouble width,
gdouble height)
{
gdouble scale;
EekBounds bounds;
gsize n_outlines;
guint i;
eek_element_get_bounds (EEK_ELEMENT(keyboard), &bounds);
if (width * bounds.height < height * bounds.width)
scale = width / bounds.width;
else
scale = height / bounds.height;
scale_bounds (EEK_ELEMENT(keyboard), scale);
n_outlines = eek_keyboard_get_n_outlines (keyboard);
for (i = 0; i < n_outlines; i++) {
EekOutline *outline = eek_keyboard_get_outline (keyboard, i);
gint j;
for (j = 0; j < outline->num_points; j++) {
outline->points[j].x *= scale;
outline->points[j].y *= scale;
}
}
}
static gboolean static gboolean
validate (const gchar **valid_path_list, validate (const gchar **valid_path_list,
gsize valid_path_list_len, gsize valid_path_list_len,

View File

@ -29,29 +29,7 @@
G_BEGIN_DECLS G_BEGIN_DECLS
#define EEK_TYPE_XML_LAYOUT (eek_xml_layout_get_type()) #define EEK_TYPE_XML_LAYOUT (eek_xml_layout_get_type())
#define EEK_XML_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEK_TYPE_XML_LAYOUT, EekXmlLayout)) G_DECLARE_DERIVABLE_TYPE (EekXmlLayout, eek_xml_layout, EEK, XML_LAYOUT, EekLayout)
#define EEK_XML_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEK_TYPE_XML_LAYOUT, EekXmlLayoutClass))
#define EEK_IS_XML_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEK_TYPE_XML_LAYOUT))
#define EEK_IS_XML_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_XML_LAYOUT))
#define EEK_XML_LAYOUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_XML_LAYOUT, EekXmlLayoutClass))
typedef struct _EekXmlLayout EekXmlLayout;
typedef struct _EekXmlLayoutClass EekXmlLayoutClass;
typedef struct _EekXmlLayoutPrivate EekXmlLayoutPrivate;
/**
* EekXmlLayout:
*
* The #EekXmlLayout structure contains only private data and should
* only be accessed using the provided API.
*/
struct _EekXmlLayout
{
/*< private >*/
EekLayout parent;
EekXmlLayoutPrivate *priv;
};
/** /**
* EekXmlLayoutClass: * EekXmlLayoutClass:

View File

@ -1,317 +0,0 @@
/*
* Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2011 Red Hat, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* SECTION: eek-xml
* @title: XML Conversion Utilities
* @short_description: #EekKeyboard to XML conversion utilities
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include <stdio.h>
#include <stdarg.h>
#include <glib/gprintf.h>
#include "eek-section.h"
#include "eek-key.h"
#include "eek-xml.h"
#include "eek-keysym.h"
#include "eek-text.h"
#define g_string_append_indent(string, indent) \
{ \
gint i; \
for (i = 0; i < (indent); i++) { \
g_string_append (string, " "); \
} \
}
void
g_string_markup_printf (GString *output, const gchar *format, ...)
{
gchar *escaped_text;
va_list ap;
va_start (ap, format);
escaped_text = g_markup_vprintf_escaped (format, ap);
va_end (ap);
g_string_append (output, escaped_text);
g_free (escaped_text);
}
struct _OutputCallbackData {
GString *output;
gint indent;
GHashTable *oref_hash;
gint key_serial;
};
typedef struct _OutputCallbackData OutputCallbackData;
static void
output_bounds (GString *output, EekBounds *bounds)
{
g_string_markup_printf (output,
"<bounds>%lf,%lf,%lf,%lf</bounds>\n",
bounds->x,
bounds->y,
bounds->width,
bounds->height);
}
static void
output_symbol_attributes (GString *output,
EekSymbol *symbol)
{
if (eek_symbol_get_name (symbol) != NULL)
g_string_markup_printf (output, " name=\"%s\"",
eek_symbol_get_name (symbol));
if (eek_symbol_get_label (symbol) != NULL)
g_string_markup_printf (output, " label=\"%s\"",
eek_symbol_get_label (symbol));
if (eek_symbol_get_category (symbol) != EEK_SYMBOL_CATEGORY_UNKNOWN)
g_string_markup_printf (output, " category=\"%s\"",
eek_symbol_category_get_name (eek_symbol_get_category (symbol)));
}
static void
output_key_callback (EekElement *element, gpointer user_data)
{
OutputCallbackData *data = user_data;
EekBounds bounds;
gint i, num_symbols;
EekSymbolMatrix *matrix;
gint column, row;
guint keycode;
gchar *id;
gulong oref;
keycode = eek_key_get_keycode (EEK_KEY(element));
if (keycode == EEK_INVALID_KEYCODE)
id = g_strdup_printf ("key%d", data->key_serial);
else
id = g_strdup_printf ("keycode%d", keycode);
data->key_serial++;
eek_key_get_index (EEK_KEY(element), &column, &row);
g_string_append_indent (data->output, data->indent);
if (eek_element_get_name (element))
g_string_markup_printf (data->output,
"<key id=\"%s\" name=\"%s\" "
"column=\"%d\" row=\"%d\">\n",
id,
eek_element_get_name (element),
column,
row);
else
g_string_markup_printf (data->output,
"<key id=\"%s\" "
"column=\"%d\" row=\"%d\">\n",
id,
column,
row);
g_free (id);
eek_element_get_bounds (element, &bounds);
g_string_append_indent (data->output, data->indent + 1);
output_bounds (data->output, &bounds);
oref = eek_key_get_oref (EEK_KEY(element));
if (oref != 0) {
g_string_append_indent (data->output, data->indent + 1);
g_string_markup_printf (data->output,
"<oref>outline%u</oref>\n",
oref);
if (!g_hash_table_lookup (data->oref_hash, (gpointer)oref))
g_hash_table_insert (data->oref_hash,
(gpointer)oref,
(gpointer)TRUE);
}
matrix = eek_key_get_symbol_matrix (EEK_KEY(element));
num_symbols = matrix->num_groups * matrix->num_levels;
if (num_symbols > 0) {
g_string_append_indent (data->output, data->indent + 1);
g_string_markup_printf (data->output,
"<symbols groups=\"%d\" levels=\"%d\">\n",
matrix->num_groups, matrix->num_levels);
for (i = 0; i < num_symbols; i++) {
EekSymbol *symbol = matrix->data[i];
g_string_append_indent (data->output, data->indent + 2);
if (EEK_IS_KEYSYM(symbol)) {
guint xkeysym = eek_keysym_get_xkeysym (EEK_KEYSYM(symbol));
g_string_markup_printf (data->output, "<keysym");
output_symbol_attributes (data->output, symbol);
if (xkeysym != EEK_INVALID_KEYSYM)
g_string_markup_printf (data->output, " keyval=\"%u\"",
xkeysym);
g_string_markup_printf (data->output, ">%s</keysym>\n",
eek_symbol_get_name (symbol));
}
else if (EEK_IS_TEXT(symbol)) {
g_string_markup_printf (data->output, "<text");
output_symbol_attributes (data->output, symbol);
g_string_markup_printf (data->output,
">%s</text>\n",
eek_text_get_text (EEK_TEXT(symbol)));
}
else {
g_string_markup_printf (data->output, "<symbol");
output_symbol_attributes (data->output, symbol);
g_string_markup_printf (data->output,
">%s</symbol>\n",
eek_symbol_get_name (symbol));
}
}
g_string_append_indent (data->output, data->indent + 1);
g_string_markup_printf (data->output, "</symbols>\n");
}
g_string_append_indent (data->output, data->indent);
g_string_markup_printf (data->output, "</key>\n");
}
static void
output_section_callback (EekElement *element, gpointer user_data)
{
OutputCallbackData *data = user_data;
EekBounds bounds;
gint angle, n_rows, i;
g_string_append_indent (data->output, data->indent);
if (eek_element_get_name (element))
g_string_markup_printf (data->output, "<section name=\"%s\">\n",
eek_element_get_name (element));
else
g_string_markup_printf (data->output, "<section>\n");
eek_element_get_bounds (element, &bounds);
g_string_append_indent (data->output, data->indent + 1);
output_bounds (data->output, &bounds);
angle = eek_section_get_angle (EEK_SECTION(element));
g_string_append_indent (data->output, data->indent + 1);
g_string_markup_printf (data->output, "<angle>%d</angle>\n", angle);
n_rows = eek_section_get_n_rows (EEK_SECTION(element));
for (i = 0; i < n_rows; i++) {
gint num_columns;
EekOrientation orientation;
eek_section_get_row (EEK_SECTION(element),
i,
&num_columns,
&orientation);
g_string_append_indent (data->output, data->indent + 1);
g_string_markup_printf (data->output, "<row>\n");
g_string_append_indent (data->output, data->indent + 2);
g_string_markup_printf (data->output, "<columns>%d</columns>\n",
num_columns);
g_string_append_indent (data->output, data->indent + 2);
g_string_markup_printf (data->output, "<orientation>%d</orientation>\n",
orientation);
g_string_append_indent (data->output, data->indent + 1);
g_string_markup_printf (data->output, "</row>\n");
}
data->indent++;
eek_container_foreach_child (EEK_CONTAINER(element),
output_key_callback,
data);
data->indent--;
g_string_append_indent (data->output, data->indent);
g_string_markup_printf (data->output, "</section>\n");
}
/**
* eek_keyboard_output:
* @keyboard: an #EekKeyboard
* @output: a GString
* @indent: an integer
*
* Convert @keyboard into the XML format and store it into @output.
*/
void
eek_keyboard_output (EekKeyboard *keyboard, GString *output, gint indent)
{
OutputCallbackData data;
EekBounds bounds;
gulong oref;
GHashTableIter iter;
g_assert (EEK_IS_KEYBOARD(keyboard));
g_string_append_indent (output, indent);
if (eek_element_get_name (EEK_ELEMENT(keyboard)))
g_string_markup_printf (output, "<?xml version=\"1.0\"?>\n"
"<keyboard version=\"%s\" id=\"%s\">\n",
EEK_XML_SCHEMA_VERSION,
eek_element_get_name (EEK_ELEMENT(keyboard)));
else
g_string_markup_printf (output, "<?xml version=\"1.0\"?>\n"
"<keyboard version=\"%s\">\n",
EEK_XML_SCHEMA_VERSION);
eek_element_get_bounds (EEK_ELEMENT(keyboard), &bounds);
g_string_append_indent (output, indent + 1);
output_bounds (output, &bounds);
data.output = output;
data.indent = indent;
data.oref_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
data.key_serial = 0;
data.indent++;
eek_container_foreach_child (EEK_CONTAINER(keyboard),
output_section_callback,
&data);
data.indent--;
g_hash_table_iter_init (&iter, data.oref_hash);
while (g_hash_table_iter_next (&iter, (gpointer *)&oref, NULL)) {
EekOutline *outline;
gint j;
outline = eek_keyboard_get_outline (keyboard, oref);
g_string_append_indent (output, indent + 1);
g_string_markup_printf (output, "<outline id=\"outline%u\">\n", oref);
g_string_append_indent (output, indent + 2);
g_string_markup_printf (output, "<corner-radius>%lf</corner-radius>\n",
outline->corner_radius);
for (j = 0; j < outline->num_points; j++) {
g_string_append_indent (output, indent + 2);
g_string_markup_printf (output, "<point>%lf,%lf</point>\n",
outline->points[j].x,
outline->points[j].y);
}
g_string_append_indent (output, indent + 1);
g_string_markup_printf (output, "</outline>\n");
}
g_hash_table_destroy (data.oref_hash);
g_string_append_indent (output, indent);
g_string_markup_printf (output, "</keyboard>\n");
}

View File

@ -1,39 +0,0 @@
/*
* Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2011 Red Hat, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(__EEK_H_INSIDE__) && !defined(EEK_COMPILATION)
#error "Only <eek/eek.h> can be included directly."
#endif
#ifndef EEK_XML_H
#define EEK_XML_H 1
#include <glib-object.h>
#include "eek-keyboard.h"
#include "eek-xml-layout.h"
G_BEGIN_DECLS
#define EEK_XML_SCHEMA_VERSION "0.90"
void eek_keyboard_output (EekKeyboard *keyboard,
GString *output,
gint indent);
G_END_DECLS
#endif /* EEK_XML_H */

View File

@ -23,9 +23,7 @@
* @title: Library Initialization * @title: Library Initialization
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */
#include "eek.h" #include "eek.h"
@ -38,9 +36,5 @@
void void
eek_init (void) eek_init (void)
{ {
g_type_init (); /* void */
g_type_class_ref (EEK_TYPE_SYMBOL);
g_type_class_ref (EEK_TYPE_KEYSYM);
g_type_class_ref (EEK_TYPE_TEXT);
} }

View File

@ -29,7 +29,6 @@
#include "eek-symbol.h" #include "eek-symbol.h"
#include "eek-keysym.h" #include "eek-keysym.h"
#include "eek-text.h" #include "eek-text.h"
#include "eek-xml.h"
#include "eek-serializable.h" #include "eek-serializable.h"
#include "eek-theme.h" #include "eek-theme.h"

39
eek/keymap.h Normal file
View File

@ -0,0 +1,39 @@
#include <gdk/gdk.h>
#include <xkbcommon/xkbcommon.h>
gboolean
squeek_keymap_get_entries_for_keyval (struct xkb_keymap *xkb_keymap,
guint keyval,
GdkKeymapKey **keys,
guint *n_keys);
static const char *keymap_header = "xkb_keymap {\n\
\n";
static const char *keymap_keycodes_header = "\
xkb_keycodes \"squeekboard\" {\n\n\
minimum = 8;\n\
maximum = 255;\n\
\n";
static const char *keymap_symbols_header = "\
xkb_symbols \"squeekboard\" {\n\
\n\
name[Group1] = \"Letters\";\n\
name[Group2] = \"Numbers/Symbols\";\n\
\n";
static const char *keymap_footer = "\
xkb_types \"squeekboard\" {\n\
\n\
type \"TWO_LEVEL\" {\n\
modifiers = Shift;\n\
map[Shift] = Level2;\n\
level_name[Level1] = \"Base\";\n\
level_name[Level2] = \"Shift\";\n\
};\n\
};\n\
\n\
xkb_compatibility \"squeekboard\" {\n\
};\n\
};";

View File

@ -65,9 +65,9 @@ static void layer_surface_configure(void *data,
uint32_t height) uint32_t height)
{ {
PhoshLayerSurface *self = data; PhoshLayerSurface *self = data;
gtk_window_resize (GTK_WINDOW (self), width, height); gtk_window_resize (GTK_WINDOW (self), width, height);
zwlr_layer_surface_v1_ack_configure(surface, serial); zwlr_layer_surface_v1_ack_configure(surface, serial);
gtk_widget_show_all (GTK_WIDGET (self));
g_signal_emit (self, signals[CONFIGURED], 0); g_signal_emit (self, signals[CONFIGURED], 0);
} }
@ -180,22 +180,39 @@ phosh_layer_surface_get_property (GObject *object,
static void static void
phosh_layer_surface_constructed (GObject *object) on_phosh_layer_surface_realized (PhoshLayerSurface *self, gpointer unused)
{ {
PhoshLayerSurface *self = PHOSH_LAYER_SURFACE (object); PhoshLayerSurfacePrivate *priv;
PhoshLayerSurfacePrivate *priv = phosh_layer_surface_get_instance_private (self);
GdkWindow *gdk_window; GdkWindow *gdk_window;
G_OBJECT_CLASS (phosh_layer_surface_parent_class)->constructed (object); g_return_if_fail (PHOSH_IS_LAYER_SURFACE (self));
gtk_window_set_decorated (GTK_WINDOW (self), FALSE); priv = phosh_layer_surface_get_instance_private (self);
/* Realize the window so we can get the GDK window */
gtk_widget_realize(GTK_WIDGET (self));
gdk_window = gtk_widget_get_window (GTK_WIDGET (self)); gdk_window = gtk_widget_get_window (GTK_WIDGET (self));
gdk_wayland_window_set_use_custom_surface (gdk_window); gdk_wayland_window_set_use_custom_surface (gdk_window);
priv->wl_surface = gdk_wayland_window_get_wl_surface (gdk_window); priv->wl_surface = gdk_wayland_window_get_wl_surface (gdk_window);
gtk_window_set_decorated (GTK_WINDOW (self), FALSE);
}
static void
on_phosh_layer_surface_mapped (PhoshLayerSurface *self, gpointer unused)
{
PhoshLayerSurfacePrivate *priv;
GdkWindow *gdk_window;
g_return_if_fail (PHOSH_IS_LAYER_SURFACE (self));
priv = phosh_layer_surface_get_instance_private (self);
if (!priv->wl_surface) {
gdk_window = gtk_widget_get_window (GTK_WIDGET (self));
gdk_wayland_window_set_use_custom_surface (gdk_window);
priv->wl_surface = gdk_wayland_window_get_wl_surface (gdk_window);
}
g_debug ("Mapped %p", priv->wl_surface);
priv->layer_surface = zwlr_layer_shell_v1_get_layer_surface(priv->layer_shell, priv->layer_surface = zwlr_layer_shell_v1_get_layer_surface(priv->layer_shell,
priv->wl_surface, priv->wl_surface,
priv->wl_output, priv->wl_output,
@ -209,8 +226,45 @@ phosh_layer_surface_constructed (GObject *object)
&layer_surface_listener, &layer_surface_listener,
self); self);
wl_surface_commit(priv->wl_surface); wl_surface_commit(priv->wl_surface);
/* Process all pending events, otherwise we end up sending ack configure
* to a not yet configured surface */
wl_display_roundtrip (gdk_wayland_display_get_wl_display (gdk_display_get_default ()));
} }
static void
on_phosh_layer_surface_unmapped (PhoshLayerSurface *self, gpointer unused)
{
PhoshLayerSurfacePrivate *priv;
g_return_if_fail (PHOSH_IS_LAYER_SURFACE (self));
priv = phosh_layer_surface_get_instance_private (self);
priv = phosh_layer_surface_get_instance_private (self);
if (priv->layer_surface) {
zwlr_layer_surface_v1_destroy(priv->layer_surface);
priv->layer_surface = NULL;
}
priv->wl_surface = NULL;
}
static void
phosh_layer_surface_constructed (GObject *object)
{
PhoshLayerSurface *self = PHOSH_LAYER_SURFACE (object);
g_signal_connect (self, "realize",
G_CALLBACK (on_phosh_layer_surface_realized),
NULL);
g_signal_connect (self, "map",
G_CALLBACK (on_phosh_layer_surface_mapped),
NULL);
g_signal_connect (self, "unmap",
G_CALLBACK (on_phosh_layer_surface_unmapped),
NULL);
}
static void static void
phosh_layer_surface_dispose (GObject *object) phosh_layer_surface_dispose (GObject *object)
{ {
@ -352,6 +406,12 @@ phosh_layer_surface_new (gpointer layer_shell,
"wl-output", wl_output); "wl-output", wl_output);
} }
/**
* phosh_layer_surface_get_surface:
*
* Get the layer layer surface or #NULL if the window
* is not yet realized.
*/
struct zwlr_layer_surface_v1 * struct zwlr_layer_surface_v1 *
phosh_layer_surface_get_layer_surface(PhoshLayerSurface *self) phosh_layer_surface_get_layer_surface(PhoshLayerSurface *self)
{ {
@ -363,6 +423,12 @@ phosh_layer_surface_get_layer_surface(PhoshLayerSurface *self)
} }
/**
* phosh_layer_surface_get_wl_surface:
*
* Get the layer wayland surface or #NULL if the window
* is not yet realized.
*/
struct wl_surface * struct wl_surface *
phosh_layer_surface_get_wl_surface(PhoshLayerSurface *self) phosh_layer_surface_get_wl_surface(PhoshLayerSurface *self)
{ {

View File

@ -1,401 +0,0 @@
/*
* Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2011 Red Hat, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* SECTION:eekboard-client
* @short_description: client interface of eekboard service
*
* The #EekboardClient class provides a client side access to eekboard-server.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include "eekboard/eekboard-client.h"
enum {
DESTROYED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0, };
G_DEFINE_TYPE (EekboardClient, eekboard_client, G_TYPE_DBUS_PROXY);
#define EEKBOARD_CLIENT_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEKBOARD_TYPE_CLIENT, EekboardClientPrivate))
struct _EekboardClientPrivate
{
GHashTable *context_hash;
};
static void send_destroy_context (EekboardClient *client,
EekboardContext *context,
GCancellable *cancellable);
static void
eekboard_client_real_destroyed (EekboardClient *self)
{
EekboardClientPrivate *priv = EEKBOARD_CLIENT_GET_PRIVATE(self);
// g_debug ("eekboard_client_real_destroyed");
g_hash_table_remove_all (priv->context_hash);
}
static void
eekboard_client_dispose (GObject *object)
{
EekboardClient *client = EEKBOARD_CLIENT(object);
EekboardClientPrivate *priv = EEKBOARD_CLIENT_GET_PRIVATE(client);
if (priv->context_hash) {
GHashTableIter iter;
gpointer key, value;
g_hash_table_iter_init (&iter, priv->context_hash);
while (g_hash_table_iter_next (&iter, &key, &value)) {
send_destroy_context (client, (EekboardContext *)value, NULL);
g_hash_table_iter_remove (&iter);
}
g_hash_table_destroy (priv->context_hash);
priv->context_hash = NULL;
}
G_OBJECT_CLASS (eekboard_client_parent_class)->dispose (object);
}
static void
eekboard_client_class_init (EekboardClientClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (gobject_class,
sizeof (EekboardClientPrivate));
klass->destroyed = eekboard_client_real_destroyed;
gobject_class->dispose = eekboard_client_dispose;
/**
* EekboardClient::destroyed:
* @eekboard: an #EekboardClient
*
* The ::destroyed signal is emitted each time the name of remote
* end is vanished.
*/
signals[DESTROYED] =
g_signal_new (I_("destroyed"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EekboardClientClass, destroyed),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
}
static void
eekboard_client_init (EekboardClient *self)
{
self->priv = EEKBOARD_CLIENT_GET_PRIVATE(self);
self->priv->context_hash =
g_hash_table_new_full (g_str_hash,
g_str_equal,
(GDestroyNotify)g_free,
(GDestroyNotify)g_object_unref);
}
static void
eekboard_name_vanished_callback (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
EekboardClient *client = user_data;
g_signal_emit_by_name (client, "destroyed", NULL);
}
/**
* eekboard_client_new:
* @connection: a #GDBusConnection
* @cancellable: a #GCancellable
*
* Create a client.
*/
EekboardClient *
eekboard_client_new (GDBusConnection *connection,
GCancellable *cancellable)
{
GInitable *initable;
GError *error;
g_assert (G_IS_DBUS_CONNECTION(connection));
error = NULL;
initable =
g_initable_new (EEKBOARD_TYPE_CLIENT,
cancellable,
&error,
"g-connection", connection,
"g-name", "org.fedorahosted.Eekboard",
"g-interface-name", "org.fedorahosted.Eekboard",
"g-object-path", "/org/fedorahosted/Eekboard",
NULL);
if (initable != NULL) {
EekboardClient *client = EEKBOARD_CLIENT (initable);
gchar *name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY(client));
if (name_owner == NULL) {
g_object_unref (client);
return NULL;
}
/* the vanished callback is called when the server is disconnected */
g_bus_watch_name_on_connection (connection,
name_owner,
G_BUS_NAME_WATCHER_FLAGS_NONE,
NULL,
eekboard_name_vanished_callback,
client,
NULL);
g_free (name_owner);
return client;
}
g_warning ("can't create client: %s", error->message);
g_error_free (error);
return NULL;
}
static void
on_context_destroyed (EekboardContext *context,
gpointer user_data)
{
EekboardClient *client = user_data;
g_hash_table_remove (client->priv->context_hash,
g_dbus_proxy_get_object_path (G_DBUS_PROXY(context)));
}
/**
* eekboard_client_create_context:
* @eekboard: an #EekboardClient
* @client_name: name of the client
* @cancellable: a #GCancellable
*
* Create a new input context.
*
* Return value: (transfer full): a newly created #EekboardContext.
*/
EekboardContext *
eekboard_client_create_context (EekboardClient *client,
const gchar *client_name,
GCancellable *cancellable)
{
GVariant *variant;
const gchar *object_path;
EekboardContext *context;
GError *error;
GDBusConnection *connection;
g_assert (EEKBOARD_IS_CLIENT(client));
g_assert (client_name);
error = NULL;
variant = g_dbus_proxy_call_sync (G_DBUS_PROXY(client),
"CreateContext",
g_variant_new ("(s)", client_name),
G_DBUS_CALL_FLAGS_NONE,
-1,
cancellable,
&error);
if (!variant) {
g_warning ("failed to call CreateContext: %s", error->message);
g_error_free (error);
return NULL;
}
g_variant_get (variant, "(&s)", &object_path);
connection = g_dbus_proxy_get_connection (G_DBUS_PROXY(client));
context = eekboard_context_new (connection, object_path, cancellable);
if (!context) {
g_variant_unref (variant);
return NULL;
}
g_hash_table_insert (client->priv->context_hash,
g_strdup (object_path),
g_object_ref (context));
g_signal_connect (context, "destroyed",
G_CALLBACK(on_context_destroyed), client);
return context;
}
static void
eekboard_async_ready_callback (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GError *error = NULL;
GVariant *result;
result = g_dbus_proxy_call_finish (G_DBUS_PROXY(source_object),
res,
&error);
if (result)
g_variant_unref (result);
else {
g_warning ("error in D-Bus proxy call: %s", error->message);
g_error_free (error);
}
}
/**
* eekboard_client_push_context:
* @eekboard: an #EekboardClient
* @context: an #EekboardContext
* @cancellable: a #GCancellable
*
* Enable the input context @context and disable the others.
*/
void
eekboard_client_push_context (EekboardClient *client,
EekboardContext *context,
GCancellable *cancellable)
{
const gchar *object_path;
g_return_if_fail (EEKBOARD_IS_CLIENT(client));
g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
object_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY(context));
context = g_hash_table_lookup (client->priv->context_hash,
object_path);
if (!context)
return;
eekboard_context_set_enabled (context, TRUE);
g_dbus_proxy_call (G_DBUS_PROXY(client),
"PushContext",
g_variant_new ("(s)", object_path),
G_DBUS_CALL_FLAGS_NONE,
-1,
cancellable,
eekboard_async_ready_callback,
NULL);
}
/**
* eekboard_client_pop_context:
* @eekboard: an #EekboardClient
* @cancellable: a #GCancellable
*
* Disable the current input context and enable the previous one.
*/
void
eekboard_client_pop_context (EekboardClient *client,
GCancellable *cancellable)
{
g_return_if_fail (EEKBOARD_IS_CLIENT(client));
g_dbus_proxy_call (G_DBUS_PROXY(client),
"PopContext",
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
cancellable,
eekboard_async_ready_callback,
NULL);
}
void
eekboard_client_show_keyboard (EekboardClient *client,
GCancellable *cancellable)
{
g_return_if_fail (EEKBOARD_IS_CLIENT(client));
g_dbus_proxy_call (G_DBUS_PROXY(client),
"ShowKeyboard",
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
cancellable,
eekboard_async_ready_callback,
NULL);
}
void
eekboard_client_hide_keyboard (EekboardClient *client,
GCancellable *cancellable)
{
g_return_if_fail (EEKBOARD_IS_CLIENT(client));
g_dbus_proxy_call (G_DBUS_PROXY(client),
"HideKeyboard",
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
cancellable,
eekboard_async_ready_callback,
NULL);
}
static void
send_destroy_context (EekboardClient *client,
EekboardContext *context,
GCancellable *cancellable)
{
const gchar *object_path;
object_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY(context));
g_dbus_proxy_call (G_DBUS_PROXY(client),
"DestroyContext",
g_variant_new ("(s)", object_path),
G_DBUS_CALL_FLAGS_NONE,
-1,
cancellable,
eekboard_async_ready_callback,
NULL);
}
/**
* eekboard_client_destroy_context:
* @eekboard: an #EekboardClient
* @context: an #EekboardContext
* @cancellable: a #GCancellable
*
* Remove @context from @eekboard.
*/
void
eekboard_client_destroy_context (EekboardClient *client,
EekboardContext *context,
GCancellable *cancellable)
{
const gchar *object_path;
g_return_if_fail (EEKBOARD_IS_CLIENT(client));
g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
object_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY(context));
g_hash_table_remove (client->priv->context_hash, object_path);
send_destroy_context (client, context, cancellable);
}

View File

@ -1,79 +0,0 @@
/*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EEKBOARD_CLIENT_H
#define EEKBOARD_CLIENT_H 1
#define __EEKBOARD_CLIENT_H_INSIDE__ 1
#include <gio/gio.h>
#include "eekboard/eekboard-context.h"
G_BEGIN_DECLS
#define EEKBOARD_TYPE_CLIENT (eekboard_client_get_type())
#define EEKBOARD_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEKBOARD_TYPE_CLIENT, EekboardClient))
#define EEKBOARD_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEKBOARD_TYPE_CLIENT, EekboardClientClass))
#define EEKBOARD_IS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEKBOARD_TYPE_CLIENT))
#define EEKBOARD_IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEKBOARD_TYPE_CLIENT))
#define EEKBOARD_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEKBOARD_TYPE_CLIENT, EekboardClientClass))
typedef struct _EekboardClient EekboardClient;
typedef struct _EekboardClientClass EekboardClientClass;
typedef struct _EekboardClientPrivate EekboardClientPrivate;
struct _EekboardClient {
/*< private >*/
GDBusProxy parent;
EekboardClientPrivate *priv;
};
struct _EekboardClientClass {
/*< private >*/
GDBusProxyClass parent_class;
/* signals */
void (* destroyed) (EekboardClient *self);
/*< private >*/
/* padding */
gpointer pdummy[23];
};
GType eekboard_client_get_type (void) G_GNUC_CONST;
EekboardClient *eekboard_client_new (GDBusConnection *connection,
GCancellable *cancellable);
EekboardContext *eekboard_client_create_context (EekboardClient *eekboard,
const gchar *client_name,
GCancellable *cancellable);
void eekboard_client_push_context (EekboardClient *eekboard,
EekboardContext *context,
GCancellable *cancellable);
void eekboard_client_pop_context (EekboardClient *eekboard,
GCancellable *cancellable);
void eekboard_client_show_keyboard (EekboardClient *eekboard,
GCancellable *cancellable);
void eekboard_client_hide_keyboard (EekboardClient *eekboard,
GCancellable *cancellable);
void eekboard_client_destroy_context (EekboardClient *eekboard,
EekboardContext *context,
GCancellable *cancellable);
G_END_DECLS
#endif /* EEKBOARD_CLIENT_H */

View File

@ -1,7 +1,7 @@
/* /*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org> * Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc. * Copyright (C) 2010-2011 Red Hat, Inc.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
@ -25,11 +25,7 @@
* implementation of eekboard input context service. * implementation of eekboard input context service.
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */
#include "eekboard/eekboard-context-service.h"
#include <fcntl.h> #include <fcntl.h>
#include <stdio.h> #include <stdio.h>
@ -38,10 +34,14 @@
#include <sys/random.h> // TODO: this is Linux-specific #include <sys/random.h> // TODO: this is Linux-specific
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
#include <gio/gio.h>
#include "eekboard/key-emitter.h" #include "eekboard/key-emitter.h"
#include "wayland.h" #include "wayland.h"
//#include "eekboard/eekboard-xklutil.h"
//#include "eek/eek-xkl.h" #include "eek/eek-xml-layout.h"
#include "eekboard/eekboard-context-service.h"
#define CSW 640 #define CSW 640
#define CSH 480 #define CSH 480
@ -80,11 +80,11 @@ struct _EekboardContextServicePrivate {
gboolean repeat_triggered; gboolean repeat_triggered;
GSettings *settings; GSettings *settings;
uint32_t hint;
uint32_t purpose;
}; };
G_DEFINE_TYPE (EekboardContextService, eekboard_context_service, G_TYPE_OBJECT); G_DEFINE_TYPE_WITH_PRIVATE (EekboardContextService, eekboard_context_service, G_TYPE_OBJECT);
static Display *display = NULL;
static EekKeyboard * static EekKeyboard *
eekboard_context_service_real_create_keyboard (EekboardContextService *self, eekboard_context_service_real_create_keyboard (EekboardContextService *self,
@ -146,17 +146,23 @@ eekboard_context_service_real_create_keyboard (EekboardContextService *self,
g_error("No context created"); g_error("No context created");
} }
struct xkb_rule_names rules = { 0 }; gchar *keymap_str = eek_keyboard_get_keymap(keyboard);
rules.layout = strdup(keyboard_type);
struct xkb_keymap *keymap = xkb_keymap_new_from_names(context, &rules, struct xkb_keymap *keymap = xkb_keymap_new_from_string(context, keymap_str,
XKB_KEYMAP_COMPILE_NO_FLAGS); XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
free(keymap_str);
xkb_context_unref(context);
if (!keymap) { if (!keymap) {
g_error("Bad keymap"); g_error("Bad keymap");
} }
keyboard->keymap = keymap; keyboard->keymap = keymap;
char *keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1);
keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1);
keyboard->keymap_len = strlen(keymap_str) + 1; keyboard->keymap_len = strlen(keymap_str) + 1;
char *path = strdup("/eek_keymap-XXXXXX");
g_autofree char *path = strdup("/eek_keymap-XXXXXX");
char *r = &path[strlen(path) - 6]; char *r = &path[strlen(path) - 6];
getrandom(r, 6, GRND_NONBLOCK); getrandom(r, 6, GRND_NONBLOCK);
for (uint i = 0; i < 6; i++) { for (uint i = 0; i < 6; i++) {
@ -211,12 +217,7 @@ eekboard_context_service_set_property (GObject *object,
context->priv->keyboard = g_value_get_object (value); context->priv->keyboard = g_value_get_object (value);
break; break;
case PROP_VISIBLE: case PROP_VISIBLE:
/*if (context->priv->keyboard) { context->priv->visible = g_value_get_boolean (value);
if (g_value_get_boolean (value))
eekboard_context_service_show_keyboard (context);
else
eekboard_context_service_hide_keyboard (context);
}*/
break; break;
case PROP_FULLSCREEN: case PROP_FULLSCREEN:
context->priv->fullscreen = g_value_get_boolean (value); context->priv->fullscreen = g_value_get_boolean (value);
@ -284,10 +285,12 @@ settings_get_layout(GSettings *settings, char **type, char **layout)
} }
} }
g_variant_iter_free(iter); g_variant_iter_free(iter);
g_variant_unref(inputs);
} }
static void static void
settings_update_layout(EekboardContextService *context) { settings_update_layout(EekboardContextService *context)
{
g_autofree gchar *keyboard_type = NULL; g_autofree gchar *keyboard_type = NULL;
g_autofree gchar *keyboard_layout = NULL; g_autofree gchar *keyboard_layout = NULL;
settings_get_layout(context->priv->settings, &keyboard_type, &keyboard_layout); settings_get_layout(context->priv->settings, &keyboard_type, &keyboard_layout);
@ -299,6 +302,17 @@ settings_update_layout(EekboardContextService *context) {
keyboard_layout = g_strdup("undefined"); keyboard_layout = g_strdup("undefined");
} }
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
switch (priv->purpose) {
case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NUMBER:
case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PHONE:
keyboard_layout = g_strdup("number");
break;
default:
;
}
// generic part follows // generic part follows
static guint keyboard_id = 0; static guint keyboard_id = 0;
EekKeyboard *keyboard = g_hash_table_lookup(context->priv->keyboard_hash, EekKeyboard *keyboard = g_hash_table_lookup(context->priv->keyboard_hash,
@ -356,9 +370,6 @@ eekboard_context_service_class_init (EekboardContextServiceClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec; GParamSpec *pspec;
g_type_class_add_private (gobject_class,
sizeof (EekboardContextServicePrivate));
klass->create_keyboard = eekboard_context_service_real_create_keyboard; klass->create_keyboard = eekboard_context_service_real_create_keyboard;
klass->show_keyboard = eekboard_context_service_real_show_keyboard; klass->show_keyboard = eekboard_context_service_real_show_keyboard;
klass->hide_keyboard = eekboard_context_service_real_hide_keyboard; klass->hide_keyboard = eekboard_context_service_real_hide_keyboard;
@ -483,51 +494,6 @@ eekboard_context_service_init (EekboardContextService *self)
} }
} }
static gboolean on_repeat_timeout (EekboardContextService *context);
static gboolean
on_repeat_timeout (EekboardContextService *context)
{
guint delay = 500; // ms
// hardcoding; needs to connect to yet another settings path because
// org.gnome.desktop.input-sources doesn't control repeating
//g_settings_get (context->priv->settings, "repeat-interval", "u", &delay);
context->priv->repeat_timeout_id =
g_timeout_add (delay,
(GSourceFunc)on_repeat_timeout,
context);
return FALSE;
}
static gboolean
on_repeat_timeout_init (EekboardContextService *context)
{
/* FIXME: clear modifiers for further key repeat; better not
depend on modifier behavior is LATCH */
eek_keyboard_set_modifiers (context->priv->keyboard, 0);
/* reschedule repeat timeout only when "repeat" option is set */
/* TODO: org.gnome.desktop.input-sources doesn't have repeat info.
* In addition, repeat is only useful when the keyboard is not in text
* input mode */
/*
if (g_settings_get_boolean (context->priv->settings, "repeat")) {
guint delay;
g_settings_get (context->priv->settings, "repeat-interval", "u", &delay);
context->priv->repeat_timeout_id =
g_timeout_add (delay,
(GSourceFunc)on_repeat_timeout,
context);
} else */
context->priv->repeat_timeout_id = 0;
return FALSE;
}
/** /**
* eekboard_context_service_enable: * eekboard_context_service_enable:
* @context: an #EekboardContextService * @context: an #EekboardContextService
@ -569,7 +535,9 @@ eekboard_context_service_show_keyboard (EekboardContextService *context)
{ {
g_return_if_fail (EEKBOARD_IS_CONTEXT_SERVICE(context)); g_return_if_fail (EEKBOARD_IS_CONTEXT_SERVICE(context));
EEKBOARD_CONTEXT_SERVICE_GET_CLASS(context)->show_keyboard (context); if (!context->priv->visible) {
EEKBOARD_CONTEXT_SERVICE_GET_CLASS(context)->show_keyboard (context);
}
} }
void void
@ -577,7 +545,9 @@ eekboard_context_service_hide_keyboard (EekboardContextService *context)
{ {
g_return_if_fail (EEKBOARD_IS_CONTEXT_SERVICE(context)); g_return_if_fail (EEKBOARD_IS_CONTEXT_SERVICE(context));
EEKBOARD_CONTEXT_SERVICE_GET_CLASS(context)->hide_keyboard (context); if (context->priv->visible) {
EEKBOARD_CONTEXT_SERVICE_GET_CLASS(context)->hide_keyboard (context);
}
} }
/** /**
@ -630,3 +600,15 @@ void eekboard_context_service_set_keymap(EekboardContextService *context,
WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
keyboard->keymap_fd, keyboard->keymap_len); keyboard->keymap_fd, keyboard->keymap_len);
} }
void eekboard_context_service_set_hint_purpose(EekboardContextService *context,
uint32_t hint, uint32_t purpose)
{
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
if (priv->hint != hint || priv->purpose != purpose) {
priv->hint = hint;
priv->purpose = purpose;
settings_update_layout(context);
}
}

View File

@ -25,6 +25,7 @@
#include <eek/eek.h> #include <eek/eek.h>
#include "virtual-keyboard-unstable-v1-client-protocol.h" #include "virtual-keyboard-unstable-v1-client-protocol.h"
#include "text-input-unstable-v3-client-protocol.h"
G_BEGIN_DECLS G_BEGIN_DECLS
@ -104,5 +105,9 @@ gboolean eekboard_context_service_get_fullscreen
void eekboard_context_service_set_keymap(EekboardContextService *context, void eekboard_context_service_set_keymap(EekboardContextService *context,
const EekKeyboard *keyboard); const EekKeyboard *keyboard);
void eekboard_context_service_set_hint_purpose(EekboardContextService *context,
uint32_t hint,
uint32_t purpose);
G_END_DECLS G_END_DECLS
#endif /* EEKBOARD_CONTEXT_SERVICE_H */ #endif /* EEKBOARD_CONTEXT_SERVICE_H */

View File

@ -24,9 +24,7 @@
* context. * context.
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */
#include "eekboard/eekboard-context.h" #include "eekboard/eekboard-context.h"
//#include "eekboard/eekboard-marshalers.h" //#include "eekboard/eekboard-marshalers.h"
@ -49,18 +47,15 @@ enum {
PROP_LAST PROP_LAST
}; };
G_DEFINE_TYPE (EekboardContext, eekboard_context, G_TYPE_DBUS_PROXY); typedef struct _EekboardContextPrivate
#define EEKBOARD_CONTEXT_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEKBOARD_TYPE_CONTEXT, EekboardContextPrivate))
struct _EekboardContextPrivate
{ {
gboolean visible; gboolean visible;
gboolean enabled; gboolean enabled;
gboolean fullscreen; gboolean fullscreen;
gint group; gint group;
}; } EekboardContextPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (EekboardContext, eekboard_context, G_TYPE_DBUS_PROXY)
static void static void
eekboard_context_real_g_signal (GDBusProxy *self, eekboard_context_real_g_signal (GDBusProxy *self,
@ -69,6 +64,7 @@ eekboard_context_real_g_signal (GDBusProxy *self,
GVariant *parameters) GVariant *parameters)
{ {
EekboardContext *context = EEKBOARD_CONTEXT (self); EekboardContext *context = EEKBOARD_CONTEXT (self);
EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
if (g_strcmp0 (signal_name, "Enabled") == 0) { if (g_strcmp0 (signal_name, "Enabled") == 0) {
g_signal_emit (context, signals[ENABLED], 0); g_signal_emit (context, signals[ENABLED], 0);
@ -111,8 +107,8 @@ eekboard_context_real_g_signal (GDBusProxy *self,
gboolean visible = FALSE; gboolean visible = FALSE;
g_variant_get (parameters, "(b)", &visible); g_variant_get (parameters, "(b)", &visible);
if (visible != context->priv->visible) { if (visible != priv->visible) {
context->priv->visible = visible; priv->visible = visible;
g_object_notify (G_OBJECT(context), "visible"); g_object_notify (G_OBJECT(context), "visible");
} }
return; return;
@ -122,8 +118,8 @@ eekboard_context_real_g_signal (GDBusProxy *self,
gint group = 0; gint group = 0;
g_variant_get (parameters, "(i)", &group); g_variant_get (parameters, "(i)", &group);
if (group != context->priv->group) { if (group != priv->group) {
context->priv->group = group; priv->group = group;
/* g_object_notify (G_OBJECT(context), "group"); */ /* g_object_notify (G_OBJECT(context), "group"); */
} }
return; return;
@ -135,13 +131,17 @@ eekboard_context_real_g_signal (GDBusProxy *self,
static void static void
eekboard_context_real_enabled (EekboardContext *self) eekboard_context_real_enabled (EekboardContext *self)
{ {
self->priv->enabled = TRUE; EekboardContextPrivate *priv = eekboard_context_get_instance_private (self);
priv->enabled = TRUE;
} }
static void static void
eekboard_context_real_disabled (EekboardContext *self) eekboard_context_real_disabled (EekboardContext *self)
{ {
self->priv->enabled = FALSE; EekboardContextPrivate *priv = eekboard_context_get_instance_private (self);
priv->enabled = FALSE;
} }
static void static void
@ -164,9 +164,11 @@ eekboard_context_get_property (GObject *object,
GParamSpec *pspec) GParamSpec *pspec)
{ {
EekboardContext *context = EEKBOARD_CONTEXT(object); EekboardContext *context = EEKBOARD_CONTEXT(object);
EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
switch (prop_id) { switch (prop_id) {
case PROP_VISIBLE: case PROP_VISIBLE:
g_value_set_boolean (value, context->priv->visible); g_value_set_boolean (value, priv->visible);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -181,9 +183,6 @@ eekboard_context_class_init (EekboardContextClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec; GParamSpec *pspec;
g_type_class_add_private (gobject_class,
sizeof (EekboardContextPrivate));
klass->enabled = eekboard_context_real_enabled; klass->enabled = eekboard_context_real_enabled;
klass->disabled = eekboard_context_real_disabled; klass->disabled = eekboard_context_real_disabled;
klass->destroyed = eekboard_context_real_destroyed; klass->destroyed = eekboard_context_real_destroyed;
@ -288,7 +287,7 @@ eekboard_context_class_init (EekboardContextClass *klass)
static void static void
eekboard_context_init (EekboardContext *self) eekboard_context_init (EekboardContext *self)
{ {
self->priv = EEKBOARD_CONTEXT_GET_PRIVATE(self); /* void */
} }
static void static void
@ -485,7 +484,9 @@ eekboard_context_set_group (EekboardContext *context,
{ {
g_return_if_fail (EEKBOARD_IS_CONTEXT(context)); g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
if (context->priv->group != group) { EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
if (priv->group != group) {
g_dbus_proxy_call (G_DBUS_PROXY(context), g_dbus_proxy_call (G_DBUS_PROXY(context),
"SetGroup", "SetGroup",
g_variant_new ("(i)", group), g_variant_new ("(i)", group),
@ -509,7 +510,10 @@ eekboard_context_get_group (EekboardContext *context,
GCancellable *cancellable) GCancellable *cancellable)
{ {
g_return_val_if_fail (EEKBOARD_IS_CONTEXT(context), 0); g_return_val_if_fail (EEKBOARD_IS_CONTEXT(context), 0);
return context->priv->group;
EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
return priv->group;
} }
/** /**
@ -526,7 +530,9 @@ eekboard_context_show_keyboard (EekboardContext *context,
{ {
g_return_if_fail (EEKBOARD_IS_CONTEXT(context)); g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
if (context->priv->enabled) { EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
if (priv->enabled) {
g_dbus_proxy_call (G_DBUS_PROXY(context), g_dbus_proxy_call (G_DBUS_PROXY(context),
"ShowKeyboard", "ShowKeyboard",
NULL, NULL,
@ -551,7 +557,9 @@ eekboard_context_hide_keyboard (EekboardContext *context,
{ {
g_return_if_fail (EEKBOARD_IS_CONTEXT(context)); g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
if (context->priv->enabled) { EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
if (priv->enabled) {
g_dbus_proxy_call (G_DBUS_PROXY(context), g_dbus_proxy_call (G_DBUS_PROXY(context),
"HideKeyboard", "HideKeyboard",
NULL, NULL,
@ -578,7 +586,9 @@ eekboard_context_press_keycode (EekboardContext *context,
{ {
g_return_if_fail (EEKBOARD_IS_CONTEXT(context)); g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
if (context->priv->enabled) { EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
if (priv->enabled) {
g_dbus_proxy_call (G_DBUS_PROXY(context), g_dbus_proxy_call (G_DBUS_PROXY(context),
"PressKeycode", "PressKeycode",
g_variant_new ("(u)", keycode), g_variant_new ("(u)", keycode),
@ -605,7 +615,9 @@ eekboard_context_release_keycode (EekboardContext *context,
{ {
g_return_if_fail (EEKBOARD_IS_CONTEXT(context)); g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
if (context->priv->enabled) { EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
if (priv->enabled) {
g_dbus_proxy_call (G_DBUS_PROXY(context), g_dbus_proxy_call (G_DBUS_PROXY(context),
"ReleaseKeycode", "ReleaseKeycode",
g_variant_new ("(u)", keycode), g_variant_new ("(u)", keycode),
@ -627,7 +639,10 @@ gboolean
eekboard_context_is_visible (EekboardContext *context) eekboard_context_is_visible (EekboardContext *context)
{ {
g_return_val_if_fail (EEKBOARD_IS_CONTEXT(context), FALSE); g_return_val_if_fail (EEKBOARD_IS_CONTEXT(context), FALSE);
return context->priv->enabled && context->priv->visible;
EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
return priv->enabled && priv->visible;
} }
/** /**
@ -644,7 +659,10 @@ eekboard_context_set_enabled (EekboardContext *context,
gboolean enabled) gboolean enabled)
{ {
g_return_if_fail (EEKBOARD_IS_CONTEXT(context)); g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
context->priv->enabled = enabled;
EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
priv->enabled = enabled;
} }
/** /**
@ -657,7 +675,10 @@ gboolean
eekboard_context_is_enabled (EekboardContext *context) eekboard_context_is_enabled (EekboardContext *context)
{ {
g_return_val_if_fail (EEKBOARD_IS_CONTEXT(context), FALSE); g_return_val_if_fail (EEKBOARD_IS_CONTEXT(context), FALSE);
return context->priv->enabled;
EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
return priv->enabled;
} }
/** /**
@ -674,7 +695,10 @@ eekboard_context_set_fullscreen (EekboardContext *context,
GCancellable *cancellable) GCancellable *cancellable)
{ {
g_return_if_fail (EEKBOARD_IS_CONTEXT(context)); g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
if (context->priv->fullscreen != fullscreen) {
EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
if (priv->fullscreen != fullscreen) {
g_dbus_proxy_call (G_DBUS_PROXY(context), g_dbus_proxy_call (G_DBUS_PROXY(context),
"SetFullscreen", "SetFullscreen",
g_variant_new ("(b)", fullscreen), g_variant_new ("(b)", fullscreen),

View File

@ -28,28 +28,7 @@
G_BEGIN_DECLS G_BEGIN_DECLS
#define EEKBOARD_TYPE_CONTEXT (eekboard_context_get_type()) #define EEKBOARD_TYPE_CONTEXT (eekboard_context_get_type())
#define EEKBOARD_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEKBOARD_TYPE_CONTEXT, EekboardContext)) G_DECLARE_DERIVABLE_TYPE (EekboardContext, eekboard_context, EEKBOARD, CONTEXT, GDBusProxy)
#define EEKBOARD_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEKBOARD_TYPE_CONTEXT, EekboardContextClass))
#define EEKBOARD_IS_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEKBOARD_TYPE_CONTEXT))
#define EEKBOARD_IS_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEKBOARD_TYPE_CONTEXT))
#define EEKBOARD_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEKBOARD_TYPE_CONTEXT, EekboardContextClass))
typedef struct _EekboardContext EekboardContext;
typedef struct _EekboardContextClass EekboardContextClass;
typedef struct _EekboardContextPrivate EekboardContextPrivate;
/**
* EekboardContext:
*
* The #EekboardContext structure contains only private data and
* should only be accessed using the provided API.
*/
struct _EekboardContext {
/*< private >*/
GDBusProxy parent;
EekboardContextPrivate *priv;
};
/** /**
* EekboardContextClass: * EekboardContextClass:

View File

@ -26,16 +26,16 @@
* implementation of eekboard service. * implementation of eekboard service.
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */
#include "eekboard/eekboard-service.h"
#include "sm.puri.OSK0.h" #include "sm.puri.OSK0.h"
#include <stdio.h> #include <stdio.h>
#include <gio/gio.h>
#include "eekboard/eekboard-service.h"
enum { enum {
PROP_0, PROP_0,
PROP_OBJECT_PATH, PROP_OBJECT_PATH,
@ -50,10 +50,8 @@ enum {
static guint signals[LAST_SIGNAL] = { 0, }; static guint signals[LAST_SIGNAL] = { 0, };
#define EEKBOARD_SERVICE_GET_PRIVATE(obj) \ typedef struct _EekboardServicePrivate
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEKBOARD_TYPE_SERVICE, EekboardServicePrivate)) {
struct _EekboardServicePrivate {
GDBusConnection *connection; GDBusConnection *connection;
SmPuriOSK0 *dbus_interface; SmPuriOSK0 *dbus_interface;
GDBusNodeInfo *introspection_data; GDBusNodeInfo *introspection_data;
@ -61,9 +59,9 @@ struct _EekboardServicePrivate {
char *object_path; char *object_path;
EekboardContextService *context; // unowned reference EekboardContextService *context; // unowned reference
}; } EekboardServicePrivate;
G_DEFINE_TYPE (EekboardService, eekboard_service, G_TYPE_OBJECT); G_DEFINE_TYPE_WITH_PRIVATE (EekboardService, eekboard_service, G_TYPE_OBJECT)
static void static void
eekboard_service_set_property (GObject *object, eekboard_service_set_property (GObject *object,
@ -72,19 +70,20 @@ eekboard_service_set_property (GObject *object,
GParamSpec *pspec) GParamSpec *pspec)
{ {
EekboardService *service = EEKBOARD_SERVICE(object); EekboardService *service = EEKBOARD_SERVICE(object);
EekboardServicePrivate *priv = eekboard_service_get_instance_private (service);
GDBusConnection *connection; GDBusConnection *connection;
switch (prop_id) { switch (prop_id) {
case PROP_OBJECT_PATH: case PROP_OBJECT_PATH:
if (service->priv->object_path) if (priv->object_path)
g_free (service->priv->object_path); g_free (priv->object_path);
service->priv->object_path = g_value_dup_string (value); priv->object_path = g_value_dup_string (value);
break; break;
case PROP_CONNECTION: case PROP_CONNECTION:
connection = g_value_get_object (value); connection = g_value_get_object (value);
if (service->priv->connection) if (priv->connection)
g_object_unref (service->priv->connection); g_object_unref (priv->connection);
service->priv->connection = g_object_ref (connection); priv->connection = g_object_ref (connection);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -99,13 +98,14 @@ eekboard_service_get_property (GObject *object,
GParamSpec *pspec) GParamSpec *pspec)
{ {
EekboardService *service = EEKBOARD_SERVICE(object); EekboardService *service = EEKBOARD_SERVICE(object);
EekboardServicePrivate *priv = eekboard_service_get_instance_private (service);
switch (prop_id) { switch (prop_id) {
case PROP_OBJECT_PATH: case PROP_OBJECT_PATH:
g_value_set_string (value, service->priv->object_path); g_value_set_string (value, priv->object_path);
break; break;
case PROP_CONNECTION: case PROP_CONNECTION:
g_value_set_object (value, service->priv->connection); g_value_set_object (value, priv->connection);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -117,20 +117,27 @@ static void
eekboard_service_dispose (GObject *object) eekboard_service_dispose (GObject *object)
{ {
EekboardService *service = EEKBOARD_SERVICE(object); EekboardService *service = EEKBOARD_SERVICE(object);
if (service->priv->connection) { EekboardServicePrivate *priv = eekboard_service_get_instance_private (service);
if (service->priv->registration_id > 0) {
g_dbus_connection_unregister_object (service->priv->connection, if (priv->connection) {
service->priv->registration_id); if (priv->registration_id > 0) {
service->priv->registration_id = 0; g_dbus_connection_unregister_object (priv->connection,
priv->registration_id);
priv->registration_id = 0;
} }
g_object_unref (service->priv->connection); g_object_unref (priv->connection);
service->priv->connection = NULL; priv->connection = NULL;
} }
if (service->priv->introspection_data) { if (priv->introspection_data) {
g_dbus_node_info_unref (service->priv->introspection_data); g_dbus_node_info_unref (priv->introspection_data);
service->priv->introspection_data = NULL; priv->introspection_data = NULL;
}
if (priv->context) {
g_signal_handlers_disconnect_by_data (priv->context, service);
priv->context = NULL;
} }
G_OBJECT_CLASS (eekboard_service_parent_class)->dispose (object); G_OBJECT_CLASS (eekboard_service_parent_class)->dispose (object);
@ -140,8 +147,9 @@ static void
eekboard_service_finalize (GObject *object) eekboard_service_finalize (GObject *object)
{ {
EekboardService *service = EEKBOARD_SERVICE(object); EekboardService *service = EEKBOARD_SERVICE(object);
EekboardServicePrivate *priv = eekboard_service_get_instance_private (service);
g_free (service->priv->object_path); g_free (priv->object_path);
G_OBJECT_CLASS (eekboard_service_parent_class)->finalize (object); G_OBJECT_CLASS (eekboard_service_parent_class)->finalize (object);
} }
@ -150,33 +158,51 @@ static gboolean
handle_set_visible(SmPuriOSK0 *object, GDBusMethodInvocation *invocation, handle_set_visible(SmPuriOSK0 *object, GDBusMethodInvocation *invocation,
gboolean arg_visible, gpointer user_data) { gboolean arg_visible, gpointer user_data) {
EekboardService *service = user_data; EekboardService *service = user_data;
if (service->priv->context) { EekboardServicePrivate *priv = eekboard_service_get_instance_private (service);
if (priv->context) {
if (arg_visible) { if (arg_visible) {
eekboard_context_service_show_keyboard (service->priv->context); eekboard_context_service_show_keyboard (priv->context);
} else { } else {
eekboard_context_service_hide_keyboard (service->priv->context); eekboard_context_service_hide_keyboard (priv->context);
} }
} }
sm_puri_osk0_complete_set_visible(object, invocation); sm_puri_osk0_complete_set_visible(object, invocation);
return TRUE; return TRUE;
} }
static void on_visible(EekboardService *service,
GParamSpec *pspec,
EekboardContextService *context)
{
gboolean visible;
EekboardServicePrivate *priv;
g_return_if_fail (EEKBOARD_IS_SERVICE (service));
g_return_if_fail (EEKBOARD_IS_CONTEXT_SERVICE (context));
priv = eekboard_service_get_instance_private (service);
g_object_get (context, "visible", &visible, NULL);
sm_puri_osk0_set_visible(priv->dbus_interface, visible);
}
static void static void
eekboard_service_constructed (GObject *object) eekboard_service_constructed (GObject *object)
{ {
EekboardService *service = EEKBOARD_SERVICE(object); EekboardService *service = EEKBOARD_SERVICE(object);
EekboardServicePrivate *priv = eekboard_service_get_instance_private (service);
service->priv->dbus_interface = sm_puri_osk0_skeleton_new(); priv->dbus_interface = sm_puri_osk0_skeleton_new();
sm_puri_osk0_set_visible(service->priv->dbus_interface, FALSE); // TODO: use actual value g_signal_connect(priv->dbus_interface, "handle-set-visible",
g_signal_connect(service->priv->dbus_interface, "handle-set-visible",
G_CALLBACK(handle_set_visible), service); G_CALLBACK(handle_set_visible), service);
if (service->priv->connection && service->priv->object_path) { if (priv->connection && priv->object_path) {
GError *error = NULL; GError *error = NULL;
if (!g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(service->priv->dbus_interface), if (!g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(priv->dbus_interface),
service->priv->connection, priv->connection,
service->priv->object_path, priv->object_path,
&error)) { &error)) {
g_warning("Error registering dbus object: %s\n", error->message); g_warning("Error registering dbus object: %s\n", error->message);
g_clear_error(&error); g_clear_error(&error);
@ -190,9 +216,6 @@ eekboard_service_class_init (EekboardServiceClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec; GParamSpec *pspec;
g_type_class_add_private (gobject_class,
sizeof (EekboardServicePrivate));
klass->create_context = NULL; klass->create_context = NULL;
gobject_class->constructed = eekboard_service_constructed; gobject_class->constructed = eekboard_service_constructed;
@ -250,8 +273,9 @@ eekboard_service_class_init (EekboardServiceClass *klass)
static void static void
eekboard_service_init (EekboardService *self) eekboard_service_init (EekboardService *self)
{ {
self->priv = EEKBOARD_SERVICE_GET_PRIVATE(self); EekboardServicePrivate *priv = eekboard_service_get_instance_private (self);
self->priv->context = NULL;
priv->context = NULL;
} }
/** /**
@ -271,7 +295,16 @@ eekboard_service_new (GDBusConnection *connection,
void void
eekboard_service_set_context(EekboardService *service, eekboard_service_set_context(EekboardService *service,
EekboardContextService *context)
{
EekboardServicePrivate *priv = eekboard_service_get_instance_private (service);
EekboardContextService *context) { g_return_if_fail (!priv->context);
service->priv->context = context;
priv->context = context;
g_signal_connect_swapped (priv->context,
"notify::visible",
G_CALLBACK(on_visible),
service);
} }

View File

@ -28,30 +28,7 @@ G_BEGIN_DECLS
#define EEKBOARD_SERVICE_INTERFACE "sm.puri.OSK0" #define EEKBOARD_SERVICE_INTERFACE "sm.puri.OSK0"
#define EEKBOARD_TYPE_SERVICE (eekboard_service_get_type()) #define EEKBOARD_TYPE_SERVICE (eekboard_service_get_type())
#define EEKBOARD_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEKBOARD_TYPE_SERVICE, EekboardService)) G_DECLARE_DERIVABLE_TYPE (EekboardService, eekboard_service, EEKBOARD, SERVICE, GObject)
#define EEKBOARD_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEKBOARD_TYPE_SERVICE, EekboardServiceClass))
#define EEKBOARD_IS_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEKBOARD_TYPE_SERVICE))
#define EEKBOARD_IS_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEKBOARD_TYPE_SERVICE))
#define EEKBOARD_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEKBOARD_TYPE_SERVICE, EekboardServiceClass))
typedef struct _EekboardService EekboardService;
typedef struct _EekboardServiceClass EekboardServiceClass;
typedef struct _EekboardServicePrivate EekboardServicePrivate;
/**
* EekboardService:
*
* Manages DBus interaction.
*
* The #EekboardService structure contains only private data and
* should only be accessed using the provided API.
*/
struct _EekboardService {
/*< private >*/
GObject parent;
EekboardServicePrivate *priv;
};
/** /**
* EekboardServiceClass: * EekboardServiceClass:

View File

@ -1,168 +0,0 @@
/*
* Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2011 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include <string.h>
#include "eekboard/eekboard-xklutil.h"
XklConfigRec *
eekboard_xkl_config_rec_from_string (const gchar *layouts)
{
XklConfigRec *rec;
gchar **strv, **l, **v;
gint i;
strv = g_strsplit (layouts, "/", -1);
g_return_val_if_fail (g_strv_length (strv) == 3, NULL);
l = g_strsplit (strv[1], ";", -1);
v = g_strdupv (l);
for (i = 0; l[i]; i++) {
gchar *layout = l[i], *variant = v[i],
*variant_start, *variant_end;
variant_start = strchr (layout, '(');
variant_end = strrchr (layout, ')');
if (variant_start && variant_end) {
*variant_start++ = '\0';
g_strlcpy (variant, variant_start,
variant_end - variant_start + 1);
} else
*variant = '\0';
}
rec = xkl_config_rec_new ();
rec->model = g_strdup (strv[0]);
rec->layouts = l;
rec->variants = v;
rec->options = g_strsplit (strv[2], ";", -1);
g_strfreev (strv);
return rec;
}
gchar *
eekboard_xkl_config_rec_to_string (XklConfigRec *rec)
{
gchar **strv, **sp, **lp, **vp, *p;
gint n_layouts;
GString *str;
n_layouts = g_strv_length (rec->layouts);
strv = g_malloc0_n (n_layouts + 2, sizeof (gchar *));
for (sp = strv, lp = rec->layouts, vp = rec->variants; *lp; sp++, lp++) {
if (*vp != NULL && **vp != '\0')
*sp = g_strdup_printf ("%s(%s)", *lp, *vp++);
else
*sp = g_strdup_printf ("%s", *lp);
}
/* MODEL/L0(V0);L1(V1);...;Ln(Vn)/O0;O1;...;On */
str = g_string_new (rec->model);
g_string_append_c (str, '/');
p = g_strjoinv (";", strv);
g_strfreev (strv);
g_string_append (str, p);
g_free (p);
g_string_append_c (str, '/');
p = g_strjoinv (";", rec->options);
g_string_append (str, p);
g_free (p);
return g_string_free (str,FALSE);
}
static XklConfigItem *
xkl_config_item_copy (const XklConfigItem *item)
{
XklConfigItem *_item = xkl_config_item_new ();
memcpy (_item->name,
item->name,
sizeof (item->name));
memcpy (_item->short_description,
item->short_description,
sizeof (item->short_description));
memcpy (_item->description,
item->description,
sizeof (item->description));
return _item;
}
static void
prepend_item (XklConfigRegistry *registry,
const XklConfigItem *item,
gpointer data)
{
GSList **list = data;
XklConfigItem *_item = xkl_config_item_copy (item);
*list = g_slist_prepend (*list, _item);
}
static gint
compare_item_by_name (gconstpointer a, gconstpointer b)
{
const XklConfigItem *ia = a, *ib = b;
return g_strcmp0 (ia->name, ib->name);
}
GSList *
eekboard_xkl_list_models (XklConfigRegistry *registry)
{
GSList *list = NULL;
xkl_config_registry_foreach_model (registry, prepend_item, &list);
return g_slist_sort (list, compare_item_by_name);
}
GSList *
eekboard_xkl_list_layouts (XklConfigRegistry *registry)
{
GSList *list = NULL;
xkl_config_registry_foreach_layout (registry, prepend_item, &list);
return g_slist_sort (list, compare_item_by_name);
}
GSList *
eekboard_xkl_list_option_groups (XklConfigRegistry *registry)
{
GSList *list = NULL;
xkl_config_registry_foreach_option_group (registry, prepend_item, &list);
return g_slist_sort (list, compare_item_by_name);
}
GSList *
eekboard_xkl_list_layout_variants (XklConfigRegistry *registry,
const gchar *layout)
{
GSList *list = NULL;
xkl_config_registry_foreach_layout_variant (registry,
layout,
prepend_item,
&list);
return g_slist_sort (list, compare_item_by_name);
}
GSList *
eekboard_xkl_list_options (XklConfigRegistry *registry,
const gchar *group)
{
GSList *list = NULL;
xkl_config_registry_foreach_option (registry, group, prepend_item, &list);
return g_slist_sort (list, compare_item_by_name);
}

View File

@ -1,39 +0,0 @@
/*
* Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2011 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#ifndef EEKBOARD_XKLUTIL_H
#define EEKBOARD_XKLUTIL_H 1
#include <libxklavier/xklavier.h>
G_BEGIN_DECLS
XklConfigRec *eekboard_xkl_config_rec_from_string (const gchar *layouts);
gchar *eekboard_xkl_config_rec_to_string (XklConfigRec *rec);
GSList *eekboard_xkl_list_models (XklConfigRegistry *registry);
GSList *eekboard_xkl_list_layouts (XklConfigRegistry *registry);
GSList *eekboard_xkl_list_option_groups (XklConfigRegistry *registry);
GSList *eekboard_xkl_list_layout_variants (XklConfigRegistry *registry,
const gchar *layout);
GSList *eekboard_xkl_list_options (XklConfigRegistry *registry,
const gchar *group);
G_END_DECLS
#endif /* EEKBOARD_XKLUTIL_H */

View File

@ -20,7 +20,6 @@
/* This file is responsible for managing keycode data and emitting keycodes. */ /* This file is responsible for managing keycode data and emitting keycodes. */
#include "eekboard/key-emitter.h" #include "eekboard/key-emitter.h"
#include "eekboard/keymap.h"
#include <gdk/gdk.h> #include <gdk/gdk.h>
@ -39,97 +38,6 @@ typedef struct {
} SeatEmitter; } SeatEmitter;
/* The following functions for keyboard mapping change are direct
translation of the code in Caribou (in libcaribou/xadapter.vala):
- get_replaced_keycode (Caribou: get_reserved_keycode)
- replace_keycode
- get_keycode_from_gdk_keymap (Caribou: best_keycode_keyval_match)
*/
/* Find an unused keycode where a keysym can be assigned. Restricted to Level 1 */
static guint
get_replaced_keycode (SeatEmitter *client)
{
guint keycode;
return 0; // FIXME: no xkb allocated yet
for (keycode = client->xkb->max_key_code;
keycode >= client->xkb->min_key_code;
--keycode) {
guint offset = client->xkb->map->key_sym_map[keycode].offset;
if (client->xkb->map->key_sym_map[keycode].kt_index[0] == XkbOneLevelIndex &&
client->xkb->map->syms[offset] != NoSymbol) {
return keycode;
}
}
return 0;
}
/* Replace keysym assigned to KEYCODE to KEYSYM. Both args are used
as in-out. If KEYCODE points to 0, this function picks a keycode
from the current map and replace the associated keysym to KEYSYM.
In that case, the replaced keycode is stored in KEYCODE and the old
keysym is stored in KEYSYM. If otherwise (KEYCODE points to
non-zero keycode), it simply changes the current map with the
specified KEYCODE and KEYSYM. */
static gboolean
replace_keycode (SeatEmitter *emitter,
guint keycode,
guint *keysym)
{
GdkDisplay *display = gdk_display_get_default ();
//Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
guint old_keysym;
int keysyms_per_keycode;
KeySym *syms;
return TRUE; // FIXME: no xkb allocated at the moment, pretending all is fine
g_return_val_if_fail (emitter->xkb->min_key_code <= keycode &&
keycode <= emitter->xkb->max_key_code,
FALSE);
g_return_val_if_fail (keysym != NULL, FALSE);
/*
* Update keyboard mapping. Wayland receives keyboard mapping as a string, so XChangeKeyboardMapping needs to translate from the symbol tbale t the string. TODO.
*
syms = XGetKeyboardMapping (xdisplay, keycode, 1, &keysyms_per_keycode);
old_keysym = syms[0];
syms[0] = *keysym;
XChangeKeyboardMapping (xdisplay, keycode, 1, syms, 1);
XSync (xdisplay, False);
XFree (syms);
*keysym = old_keysym;
*/
return TRUE;
}
static gboolean
get_keycode_from_gdk_keymap (SeatEmitter *emitter,
guint keysym,
guint *keycode,
guint *modifiers)
{
GdkKeymapKey *keys, *best_match = NULL;
guint n_keys, i;
if (!squeek_keymap_get_entries_for_keyval (emitter->keymap, keysym, &keys, &n_keys))
return FALSE;
for (i = 0; i < n_keys; i++)
if ((guint)keys[i].group == emitter->group)
best_match = &keys[i];
if (!best_match) {
g_free (keys);
return FALSE;
}
*keycode = best_match->keycode;
*modifiers = best_match->level == 1 ? EEK_SHIFT_MASK : 0;
g_free (keys);
return TRUE;
}
int send_virtual_keyboard_key( int send_virtual_keyboard_key(
struct zwp_virtual_keyboard_v1 *keyboard, struct zwp_virtual_keyboard_v1 *keyboard,
unsigned int keycode, unsigned int keycode,
@ -142,8 +50,8 @@ int send_virtual_keyboard_key(
static void static void
send_fake_modifiers_events (SeatEmitter *emitter, send_fake_modifiers_events (SeatEmitter *emitter,
EekModifierType modifiers, EekModifierType modifiers,
uint32_t timestamp) uint32_t timestamp)
{ {
(void)timestamp; (void)timestamp;
@ -160,95 +68,6 @@ send_fake_modifiers_events (SeatEmitter *emitter,
zwp_virtual_keyboard_v1_modifiers(emitter->virtual_keyboard, proto_modifiers, 0, 0, emitter->group); zwp_virtual_keyboard_v1_modifiers(emitter->virtual_keyboard, proto_modifiers, 0, 0, emitter->group);
} }
static void
send_fake_key_event (SeatEmitter *emitter,
guint xkeysym,
guint keyboard_modifiers,
gboolean pressed,
uint32_t timestamp)
{
EekModifierType modifiers;
guint old_keysym = xkeysym;
g_return_if_fail (xkeysym > 0);
guint keycode;
if (!get_keycode_from_gdk_keymap (emitter, xkeysym, &keycode, &modifiers)) {
keycode = get_replaced_keycode (emitter);
if (keycode == 0) {
g_warning ("no available keycode to replace");
return;
}
if (!replace_keycode (emitter, keycode, &old_keysym)) {
g_warning ("failed to lookup X keysym %X", xkeysym);
return;
}
}
/* Clear level shift modifiers */
keyboard_modifiers &= (unsigned)~EEK_SHIFT_MASK;
keyboard_modifiers &= (unsigned)~EEK_LOCK_MASK;
/* FIXME: may need to remap ISO_Level3_Shift and NumLock */
modifiers |= keyboard_modifiers;
send_fake_modifiers_events (emitter, modifiers, timestamp);
// There's something magical about subtracting/adding 8 to keycodes for some reason
send_virtual_keyboard_key (emitter->virtual_keyboard, keycode - 8, (unsigned)pressed, timestamp);
send_fake_modifiers_events (emitter, modifiers, timestamp);
if (old_keysym != xkeysym)
replace_keycode (emitter, keycode, &old_keysym);
}
static void
send_fake_key_events (SeatEmitter *emitter,
EekSymbol *symbol,
EekModifierType keyboard_modifiers,
gboolean pressed,
uint32_t timestamp)
{
/* Ignore modifier keys */
if (eek_symbol_is_modifier (symbol))
return;
/* If symbol is a text, convert chars in it to keysym */
if (EEK_IS_TEXT(symbol)) {
const gchar *utf8 = eek_text_get_text (EEK_TEXT(symbol));
printf("Attempting to send text %s\n", utf8);
/* FIXME:
glong items_written;
gunichar *ucs4 = g_utf8_to_ucs4_fast (utf8, -1, &items_written);
gint i;
for (i = 0; i < items_written; i++) {
guint xkeysym;
EekKeysym *keysym;
gchar *name;
name = g_strdup_printf ("U%04X", ucs4[i]);
xkeysym = XStringToKeysym (name); // TODO: use xkb_get_keysym_from_name
g_free (name);
keysym = eek_keysym_new (xkeysym);
send_fake_key_events (client,
EEK_SYMBOL(keysym),
keyboard_modifiers);
}
g_free (ucs4);
*/
return;
}
if (EEK_IS_KEYSYM(symbol)) {
guint xkeysym = eek_keysym_get_xkeysym (EEK_KEYSYM(symbol));
send_fake_key_event (emitter, xkeysym, keyboard_modifiers, pressed, timestamp);
}
}
/* Finds the first key code for each modifier and saves it in modifier_keycodes */ /* Finds the first key code for each modifier and saves it in modifier_keycodes */
static void static void
update_modifier_info (SeatEmitter *client) update_modifier_info (SeatEmitter *client)
@ -283,6 +102,26 @@ update_modifier_info (SeatEmitter *client)
}*/ }*/
} }
static void
send_fake_key (SeatEmitter *emitter,
EekKeyboard *keyboard,
guint keycode,
guint keyboard_modifiers,
gboolean pressed,
uint32_t timestamp)
{
uint32_t proto_modifiers = 0;
guint level = eek_element_get_level(EEK_ELEMENT(keyboard));
uint32_t group = (level / 2);
if (keyboard_modifiers & EEK_SHIFT_MASK)
proto_modifiers |= 1<<MOD_IDX_SHIFT;
zwp_virtual_keyboard_v1_modifiers(emitter->virtual_keyboard, proto_modifiers, 0, 0, group);
send_virtual_keyboard_key (emitter->virtual_keyboard, keycode - 8, (unsigned)pressed, timestamp);
zwp_virtual_keyboard_v1_modifiers(emitter->virtual_keyboard, proto_modifiers, 0, 0, group);
}
void void
emit_key_activated (EekboardContextService *manager, emit_key_activated (EekboardContextService *manager,
EekKeyboard *keyboard, EekKeyboard *keyboard,
@ -323,5 +162,5 @@ emit_key_activated (EekboardContextService *manager,
emitter.virtual_keyboard = manager->virtual_keyboard; emitter.virtual_keyboard = manager->virtual_keyboard;
emitter.keymap = keyboard->keymap; emitter.keymap = keyboard->keymap;
update_modifier_info (&emitter); update_modifier_info (&emitter);
send_fake_key_events (&emitter, symbol, modifiers, pressed, timestamp); send_fake_key (&emitter, keyboard, keycode, modifiers, pressed, timestamp);
} }

View File

@ -3,7 +3,6 @@
#include <inttypes.h> #include <inttypes.h>
#include <glib.h> #include <glib.h>
#include <X11/XKBlib.h>
#include "eek/eek.h" #include "eek/eek.h"

View File

@ -1,66 +0,0 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2000 Red Hat, Inc.
* Copyright (C) 2019 Purism, SPC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Modified for squeekboard based on GTK
*/
#include "keymap.h"
gboolean
squeek_keymap_get_entries_for_keyval (struct xkb_keymap *xkb_keymap,
guint keyval,
GdkKeymapKey **keys,
guint *n_keys)
{
GArray *retval;
guint keycode;
xkb_keycode_t min_keycode, max_keycode;
retval = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
min_keycode = xkb_keymap_min_keycode (xkb_keymap);
max_keycode = xkb_keymap_max_keycode (xkb_keymap);
for (keycode = min_keycode; keycode < max_keycode; keycode++)
{
xkb_layout_index_t num_layouts, layout;
num_layouts = xkb_keymap_num_layouts_for_key (xkb_keymap, keycode);
for (layout = 0; layout < num_layouts; layout++)
{
xkb_layout_index_t num_levels, level;
num_levels = xkb_keymap_num_levels_for_key (xkb_keymap, keycode, layout);
for (level = 0; level < num_levels; level++)
{
const xkb_keysym_t *syms;
gint num_syms, sym;
num_syms = xkb_keymap_key_get_syms_by_level (xkb_keymap, keycode, layout, level, &syms);
for (sym = 0; sym < num_syms; sym++)
{
if (syms[sym] == keyval)
{
GdkKeymapKey key;
key.keycode = keycode;
key.group = (gint)layout;
key.level = (gint)level;
g_array_append_val (retval, key);
}
}
}
}
}
*n_keys = retval->len;
*keys = (GdkKeymapKey*) g_array_free (retval, FALSE);
return TRUE;
}

View File

@ -1,8 +0,0 @@
#include <gdk/gdk.h>
#include <xkbcommon/xkbcommon.h>
gboolean
squeek_keymap_get_entries_for_keyval (struct xkb_keymap *xkb_keymap,
guint keyval,
GdkKeymapKey **keys,
guint *n_keys);

View File

@ -3,12 +3,28 @@ project(
'c', 'rust', 'c', 'rust',
version: '1.0.10', version: '1.0.10',
license: 'GPLv3', license: 'GPLv3',
meson_version: '>=0.43.0', meson_version: '>=0.49.0',
default_options: [ 'warning_level=1', 'buildtype=debugoptimized', 'c_std=gnu11' ], default_options: [
'warning_level=1',
'buildtype=debugoptimized',
'c_std=gnu11'
]
)
add_project_arguments(
[
'-Werror=implicit-function-declaration',
'-Werror=implicit-fallthrough=3',
'-Werror=maybe-uninitialized',
# '-Werror=missing-field-initializers', // fix eek-unicode-keysym-entries first
],
language: 'c'
) )
i18n = import('i18n') i18n = import('i18n')
conf_data = configuration_data()
if get_option('buildtype').startswith('debug') if get_option('buildtype').startswith('debug')
add_project_arguments('-DDEBUG=1', language : 'c') add_project_arguments('-DDEBUG=1', language : 'c')
endif endif
@ -26,8 +42,19 @@ else
endif endif
dbusdir = join_paths(depdatadir, 'dbus-1/interfaces') dbusdir = join_paths(depdatadir, 'dbus-1/interfaces')
summary = [
'',
'------------------',
'squeekboard @0@'.format(meson.project_version()),
'',
'------------------',
''
]
message('\n'.join(summary))
subdir('data') subdir('data')
subdir('protocols') subdir('protocols')
subdir('eek') subdir('eek')
subdir('src') subdir('src')
subdir('po') subdir('po')
subdir('tests')

View File

@ -1 +1,8 @@
option('depdatadir', type : 'string', value : '', description : 'System data path. Will be searched for definitions instead of datadir when provided') option('depdatadir',
type : 'string',
value : '',
description : 'System data path. Will be searched for definitions instead of datadir when provided')
option('tests',
type: 'boolean', value: true,
description: 'Whether to compile unit tests')

View File

@ -11,10 +11,10 @@ gen_scanner_client_code = generator(wl_scanner,
wl_protos = [ wl_protos = [
wl_protocol_dir + '/stable/xdg-shell/xdg-shell.xml', wl_protocol_dir + '/stable/xdg-shell/xdg-shell.xml',
wl_protocol_dir + '/unstable/text-input/text-input-unstable-v3.xml',
'wlr-layer-shell-unstable-v1.xml', 'wlr-layer-shell-unstable-v1.xml',
'virtual-keyboard-unstable-v1.xml', 'virtual-keyboard-unstable-v1.xml',
'input-method-unstable-v2.xml', 'input-method-unstable-v2.xml',
'text-input-unstable-v3.xml'
] ]
wl_proto_sources = [] wl_proto_sources = []
foreach proto: wl_protos foreach proto: wl_protos

View File

@ -0,0 +1,441 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="text_input_unstable_v3">
<copyright>
Copyright © 2012, 2013 Intel Corporation
Copyright © 2015, 2016 Jan Arne Petersen
Copyright © 2017, 2018 Red Hat, Inc.
Copyright © 2018 Purism SPC
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
the copyright holders not be used in advertising or publicity
pertaining to distribution of the software without specific,
written prior permission. The copyright holders make no
representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied
warranty.
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
</copyright>
<description summary="Protocol for composing text">
This protocol allows compositors to act as input methods and to send text
to applications. A text input object is used to manage state of what are
typically text entry fields in the application.
This document adheres to the RFC 2119 when using words like "must",
"should", "may", etc.
Warning! The protocol described in this file is experimental and
backward incompatible changes may be made. Backward compatible changes
may be added together with the corresponding interface version bump.
Backward incompatible changes are done by bumping the version number in
the protocol and interface names and resetting the interface version.
Once the protocol is to be declared stable, the 'z' prefix and the
version number in the protocol and interface names are removed and the
interface version number is reset.
</description>
<interface name="zwp_text_input_v3" version="1">
<description summary="text input">
The zwp_text_input_v3 interface represents text input and input methods
associated with a seat. It provides enter/leave events to follow the
text input focus for a seat.
Requests are used to enable/disable the text-input object and set
state information like surrounding and selected text or the content type.
The information about the entered text is sent to the text-input object
via the preedit_string and commit_string events.
Text is valid UTF-8 encoded, indices and lengths are in bytes. Indices
must not point to middle bytes inside a code point: they must either
point to the first byte of a code point or to the end of the buffer.
Lengths must be measured between two valid indices.
Focus moving throughout surfaces will result in the emission of
zwp_text_input_v3.enter and zwp_text_input_v3.leave events. The focused
surface must commit zwp_text_input_v3.enable and
zwp_text_input_v3.disable requests as the keyboard focus moves across
editable and non-editable elements of the UI. Those two requests are not
expected to be paired with each other, the compositor must be able to
handle consecutive series of the same request.
State is sent by the state requests (set_surrounding_text,
set_content_type and set_cursor_rectangle) and a commit request. After an
enter event or disable request all state information is invalidated and
needs to be resent by the client.
</description>
<request name="destroy" type="destructor">
<description summary="Destroy the wp_text_input">
Destroy the wp_text_input object. Also disables all surfaces enabled
through this wp_text_input object.
</description>
</request>
<request name="enable">
<description summary="Request text input to be enabled">
Requests text input on the surface previously obtained from the enter
event.
This request must be issued every time the active text input changes
to a new one, including within the current surface. Use
zwp_text_input_v3.disable when there is no longer any input focus on
the current surface.
This request resets all state associated with previous enable, disable,
set_surrounding_text, set_text_change_cause, set_content_type, and
set_cursor_rectangle requests, as well as the state associated with
preedit_string, commit_string, and delete_surrounding_text events.
The set_surrounding_text, set_content_type and set_cursor_rectangle
requests must follow if the text input supports the necessary
functionality.
State set with this request is double-buffered. It will get applied on
the next zwp_text_input_v3.commit request, and stay valid until the
next committed enable or disable request.
The changes must be applied by the compositor after issuing a
zwp_text_input_v3.commit request.
</description>
</request>
<request name="disable">
<description summary="Disable text input on a surface">
Explicitly disable text input on the current surface (typically when
there is no focus on any text entry inside the surface).
State set with this request is double-buffered. It will get applied on
the next zwp_text_input_v3.commit request.
</description>
</request>
<request name="set_surrounding_text">
<description summary="sets the surrounding text">
Sets the surrounding plain text around the input, excluding the preedit
text.
The client should notify the compositor of any changes in any of the
values carried with this request, including changes caused by handling
incoming text-input events as well as changes caused by other
mechanisms like keyboard typing.
If the client is unaware of the text around the cursor, it should not
issue this request, to signify lack of support to the compositor.
Text is UTF-8 encoded, and should include the cursor position, the
complete selection and additional characters before and after them.
There is a maximum length of wayland messages, so text can not be
longer than 4000 bytes.
Cursor is the byte offset of the cursor within text buffer.
Anchor is the byte offset of the selection anchor within text buffer.
If there is no selected text, anchor is the same as cursor.
If any preedit text is present, it is replaced with a cursor for the
purpose of this event.
Values set with this request are double-buffered. They will get applied
on the next zwp_text_input_v3.commit request, and stay valid until the
next committed enable or disable request.
The initial state for affected fields is empty, meaning that the text
input does not support sending surrounding text. If the empty values
get applied, subsequent attempts to change them may have no effect.
</description>
<arg name="text" type="string"/>
<arg name="cursor" type="int"/>
<arg name="anchor" type="int"/>
</request>
<enum name="change_cause">
<description summary="text change reason">
Reason for the change of surrounding text or cursor posision.
</description>
<entry name="input_method" value="0" summary="input method caused the change"/>
<entry name="other" value="1" summary="something else than the input method caused the change"/>
</enum>
<request name="set_text_change_cause">
<description summary="indicates the cause of surrounding text change">
Tells the compositor why the text surrounding the cursor changed.
Whenever the client detects an external change in text, cursor, or
anchor posision, it must issue this request to the compositor. This
request is intended to give the input method a chance to update the
preedit text in an appropriate way, e.g. by removing it when the user
starts typing with a keyboard.
cause describes the source of the change.
The value set with this request is double-buffered. It must be applied
and reset to initial at the next zwp_text_input_v3.commit request.
The initial value of cause is input_method.
</description>
<arg name="cause" type="uint" enum="change_cause"/>
</request>
<enum name="content_hint" bitfield="true">
<description summary="content hint">
Content hint is a bitmask to allow to modify the behavior of the text
input.
</description>
<entry name="none" value="0x0" summary="no special behavior"/>
<entry name="completion" value="0x1" summary="suggest word completions"/>
<entry name="spellcheck" value="0x2" summary="suggest word corrections"/>
<entry name="auto_capitalization" value="0x4" summary="switch to uppercase letters at the start of a sentence"/>
<entry name="lowercase" value="0x8" summary="prefer lowercase letters"/>
<entry name="uppercase" value="0x10" summary="prefer uppercase letters"/>
<entry name="titlecase" value="0x20" summary="prefer casing for titles and headings (can be language dependent)"/>
<entry name="hidden_text" value="0x40" summary="characters should be hidden"/>
<entry name="sensitive_data" value="0x80" summary="typed text should not be stored"/>
<entry name="latin" value="0x100" summary="just Latin characters should be entered"/>
<entry name="multiline" value="0x200" summary="the text input is multiline"/>
</enum>
<enum name="content_purpose">
<description summary="content purpose">
The content purpose allows to specify the primary purpose of a text
input.
This allows an input method to show special purpose input panels with
extra characters or to disallow some characters.
</description>
<entry name="normal" value="0" summary="default input, allowing all characters"/>
<entry name="alpha" value="1" summary="allow only alphabetic characters"/>
<entry name="digits" value="2" summary="allow only digits"/>
<entry name="number" value="3" summary="input a number (including decimal separator and sign)"/>
<entry name="phone" value="4" summary="input a phone number"/>
<entry name="url" value="5" summary="input an URL"/>
<entry name="email" value="6" summary="input an email address"/>
<entry name="name" value="7" summary="input a name of a person"/>
<entry name="password" value="8" summary="input a password (combine with sensitive_data hint)"/>
<entry name="pin" value="9" summary="input is a numeric password (combine with sensitive_data hint)"/>
<entry name="date" value="10" summary="input a date"/>
<entry name="time" value="11" summary="input a time"/>
<entry name="datetime" value="12" summary="input a date and time"/>
<entry name="terminal" value="13" summary="input for a terminal"/>
</enum>
<request name="set_content_type">
<description summary="set content purpose and hint">
Sets the content purpose and content hint. While the purpose is the
basic purpose of an input field, the hint flags allow to modify some of
the behavior.
Values set with this request are double-buffered. They will get applied
on the next zwp_text_input_v3.commit request.
Subsequent attempts to update them may have no effect. The values
remain valid until the next committed enable or disable request.
The initial value for hint is none, and the initial value for purpose
is normal.
</description>
<arg name="hint" type="uint" enum="content_hint"/>
<arg name="purpose" type="uint" enum="content_purpose"/>
</request>
<request name="set_cursor_rectangle">
<description summary="set cursor position">
Marks an area around the cursor as a x, y, width, height rectangle in
surface local coordinates.
Allows the compositor to put a window with word suggestions near the
cursor, without obstructing the text being input.
If the client is unaware of the position of edited text, it should not
issue this request, to signify lack of support to the compositor.
Values set with this request are double-buffered. They will get applied
on the next zwp_text_input_v3.commit request, and stay valid until the
next committed enable or disable request.
The initial values describing a cursor rectangle are empty. That means
the text input does not support describing the cursor area. If the
empty values get applied, subsequent attempts to change them may have
no effect.
</description>
<arg name="x" type="int"/>
<arg name="y" type="int"/>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
</request>
<request name="commit">
<description summary="commit state">
Atomically applies state changes recently sent to the compositor.
The commit request establishes and updates the state of the client, and
must be issued after any changes to apply them.
Text input state (enabled status, content purpose, content hint,
surrounding text and change cause, cursor rectangle) is conceptually
double-buffered within the context of a text input, i.e. between a
committed enable request and the following committed enable or disable
request.
Protocol requests modify the pending state, as opposed to the current
state in use by the input method. A commit request atomically applies
all pending state, replacing the current state. After commit, the new
pending state is as documented for each related request.
Requests are applied in the order of arrival.
Neither current nor pending state are modified unless noted otherwise.
The compositor must count the number of commit requests coming from
each zwp_text_input_v3 object and use the count as the serial in done
events.
</description>
</request>
<event name="enter">
<description summary="enter event">
Notification that this seat's text-input focus is on a certain surface.
When the seat has the keyboard capability the text-input focus follows
the keyboard focus. This event sets the current surface for the
text-input object.
</description>
<arg name="surface" type="object" interface="wl_surface"/>
</event>
<event name="leave">
<description summary="leave event">
Notification that this seat's text-input focus is no longer on a
certain surface. The client should reset any preedit string previously
set.
The leave notification clears the current surface. It is sent before
the enter notification for the new focus.
When the seat has the keyboard capability the text-input focus follows
the keyboard focus.
</description>
<arg name="surface" type="object" interface="wl_surface"/>
</event>
<event name="preedit_string">
<description summary="pre-edit">
Notify when a new composing text (pre-edit) should be set at the
current cursor position. Any previously set composing text must be
removed. Any previously existing selected text must be removed.
The argument text contains the pre-edit string buffer.
The parameters cursor_begin and cursor_end are counted in bytes
relative to the beginning of the submitted text buffer. Cursor should
be hidden when both are equal to -1.
They could be represented by the client as a line if both values are
the same, or as a text highlight otherwise.
Values set with this event are double-buffered. They must be applied
and reset to initial on the next zwp_text_input_v3.done event.
The initial value of text is an empty string, and cursor_begin,
cursor_end and cursor_hidden are all 0.
</description>
<arg name="text" type="string" allow-null="true"/>
<arg name="cursor_begin" type="int"/>
<arg name="cursor_end" type="int"/>
</event>
<event name="commit_string">
<description summary="text commit">
Notify when text should be inserted into the editor widget. The text to
commit could be either just a single character after a key press or the
result of some composing (pre-edit).
Values set with this event are double-buffered. They must be applied
and reset to initial on the next zwp_text_input_v3.done event.
The initial value of text is an empty string.
</description>
<arg name="text" type="string" allow-null="true"/>
</event>
<event name="delete_surrounding_text">
<description summary="delete surrounding text">
Notify when the text around the current cursor position should be
deleted.
Before_length and after_length are the number of bytes before and after
the current cursor index (excluding the selection) to delete.
If a preedit text is present, in effect before_length is counted from
the beginning of it, and after_length from its end (see done event
sequence).
Values set with this event are double-buffered. They must be applied
and reset to initial on the next zwp_text_input_v3.done event.
The initial values of both before_length and after_length are 0.
</description>
<arg name="before_length" type="uint" summary="length of text before current cursor position"/>
<arg name="after_length" type="uint" summary="length of text after current cursor position"/>
</event>
<event name="done">
<description summary="apply changes">
Instruct the application to apply changes to state requested by the
preedit_string, commit_string and delete_surrounding_text events. The
state relating to these events is double-buffered, and each one
modifies the pending state. This event replaces the current state with
the pending state.
The application must proceed by evaluating the changes in the following
order:
1. Replace existing preedit string with the cursor.
2. Delete requested surrounding text.
3. Insert commit string with the cursor at its end.
4. Calculate surrounding text to send.
5. Insert new preedit text in cursor position.
6. Place cursor inside preedit text.
The serial number reflects the last state of the zwp_text_input_v3
object known to the compositor. The value of the serial argument must
be equal to the number of commit requests already issued on that object.
When the client receives a done event with a serial different than the
number of past commit requests, it must proceed as normal, except it
should not change the current state of the zwp_text_input_v3 object.
</description>
<arg name="serial" type="uint"/>
</event>
</interface>
<interface name="zwp_text_input_manager_v3" version="1">
<description summary="text input manager">
A factory for text-input objects. This object is a global singleton.
</description>
<request name="destroy" type="destructor">
<description summary="Destroy the wp_text_input_manager">
Destroy the wp_text_input_manager object.
</description>
</request>
<request name="get_text_input">
<description summary="create a new text input object">
Creates a new text-input object for a given seat.
</description>
<arg name="id" type="new_id" interface="zwp_text_input_v3"/>
<arg name="seat" type="object" interface="wl_seat"/>
</request>
</interface>
</protocol>

1350
src/bitflags.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,320 +0,0 @@
/*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include <stdlib.h>
#ifdef HAVE_ATSPI
#include <dbus/dbus.h>
#include <atspi/atspi.h>
#endif /* HAVE_ATSPI */
#ifdef HAVE_IBUS
#include <ibus.h>
#endif /* HAVE_IBUS */
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include "eekboard/eekboard-client.h"
#include "client.h"
static gboolean opt_system = FALSE;
static gboolean opt_session = FALSE;
static gchar *opt_address = NULL;
static gboolean opt_focus = FALSE;
#ifdef HAVE_ATSPI
static gboolean opt_keystroke = FALSE;
#endif /* HAVE_ATSPI */
static gchar *opt_keyboards = NULL;
static gboolean opt_fullscreen = FALSE;
static const GOptionEntry options[] = {
{"system", 'y', 0, G_OPTION_ARG_NONE, &opt_system,
N_("Connect to the system bus")},
{"session", 'e', 0, G_OPTION_ARG_NONE, &opt_session,
N_("Connect to the session bus")},
{"address", 'a', 0, G_OPTION_ARG_STRING, &opt_address,
N_("Connect to the given D-Bus address")},
#if ENABLE_FOCUS_LISTENER
{"listen-focus", 'f', 0, G_OPTION_ARG_NONE, &opt_focus,
N_("Listen focus change events")},
#endif /* ENABLE_FOCUS_LISTENER */
#ifdef HAVE_ATSPI
{"listen-keystroke", 's', 0, G_OPTION_ARG_NONE, &opt_keystroke,
N_("Listen keystroke events with AT-SPI")},
#endif /* HAVE_ATSPI */
{"keyboards", 'k', 0, G_OPTION_ARG_STRING, &opt_keyboards,
N_("Specify keyboards (comma separated)")},
{"fullscreen", 'F', 0, G_OPTION_ARG_NONE, &opt_fullscreen,
N_("Create window in fullscreen mode")},
{NULL}
};
static void
on_context_destroyed (EekboardContext *context,
gpointer user_data)
{
gtk_main_quit ();
}
static void
on_destroyed (EekboardClient *eekboard,
gpointer user_data)
{
gtk_main_quit ();
}
enum FocusListenerType {
FOCUS_NONE,
FOCUS_ATSPI,
FOCUS_IBUS
};
static gboolean
set_keyboards (SeatEmitter *client,
const gchar * const *keyboards)
{
if (g_strv_length ((gchar **)keyboards) == 0) {
if (!client_enable_xkl (client)) {
g_printerr ("Can't register xklavier event listeners\n");
return FALSE;
}
} else {
if (!client_set_keyboards (client, keyboards)) {
gchar *str = g_strjoinv (", ", (gchar **)keyboards);
g_printerr ("Can't set keyboards \"%s\"\n", str);
g_free (str);
return FALSE;
}
}
return TRUE;
}
int
main (int argc, char **argv)
{
SeatEmitter *client = NULL;
EekboardClient *eekboard;
EekboardContext *context;
GBusType bus_type;
GDBusConnection *connection;
GError *error;
GOptionContext *option_context;
gint focus;
GSettings *settings = NULL;
gchar **keyboards = NULL;
gint retval = 0;
if (!gtk_init_check (&argc, &argv)) {
g_printerr ("Can't init GTK\n");
exit (1);
}
eek_init ();
option_context = g_option_context_new ("eekboard-desktop-client");
g_option_context_add_main_entries (option_context, options, NULL);
g_option_context_parse (option_context, &argc, &argv, NULL);
g_option_context_free (option_context);
if (opt_system)
bus_type = G_BUS_TYPE_SYSTEM;
else if (opt_address)
bus_type = G_BUS_TYPE_NONE;
else
bus_type = G_BUS_TYPE_SESSION;
switch (bus_type) {
case G_BUS_TYPE_SYSTEM:
error = NULL;
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
if (connection == NULL) {
g_printerr ("Can't connect to the system bus: %s\n",
error->message);
g_error_free (error);
exit (1);
}
break;
case G_BUS_TYPE_SESSION:
error = NULL;
connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
if (connection == NULL) {
g_printerr ("Can't connect to the session bus: %s\n",
error->message);
g_error_free (error);
exit (1);
}
break;
case G_BUS_TYPE_NONE:
error = NULL;
connection = g_dbus_connection_new_for_address_sync (opt_address,
0,
NULL,
NULL,
&error);
if (connection == NULL) {
g_printerr ("Can't connect to the bus at %s: %s\n",
opt_address,
error->message);
g_error_free (error);
exit (1);
}
break;
default:
g_assert_not_reached ();
break;
}
client = client_new (connection);
g_object_unref (connection);
if (client == NULL) {
g_printerr ("Can't create a client\n");
exit (1);
}
settings = g_settings_new ("org.fedorahosted.eekboard");
focus = FOCUS_NONE;
if (opt_focus) {
gchar *focus_listener = g_settings_get_string (settings,
"focus-listener");
const struct {
const gchar *name;
enum FocusListenerType type;
} focus_listeners[] = {
#ifdef HAVE_ATSPI
{ "atspi", FOCUS_ATSPI },
#endif
#ifdef HAVE_IBUS
{ "ibus", FOCUS_IBUS },
#endif
{ NULL }
};
gint i;
focus = FOCUS_NONE;
for (i = 0; focus_listeners[i].name; i++) {
if (g_strcmp0 (focus_listener, focus_listeners[i].name) == 0)
focus = focus_listeners[i].type;
}
if (focus == FOCUS_NONE) {
g_printerr ("Unknown focus listener \"%s\". "
"Try \"atspi\" or \"ibus\"\n", focus_listener);
retval = 1;
goto out;
}
}
#ifdef HAVE_ATSPI
if (focus == FOCUS_ATSPI || opt_keystroke) {
GSettings *desktop_settings =
g_settings_new ("org.gnome.desktop.interface");
gboolean accessibility_enabled =
g_settings_get_boolean (desktop_settings, "toolkit-accessibility");
g_object_unref (desktop_settings);
if (accessibility_enabled) {
if (atspi_init () != 0) {
g_printerr ("Can't init AT-SPI 2\n");
retval = 1;
goto out;
}
if (focus == FOCUS_ATSPI &&
!client_enable_atspi_focus (client)) {
g_printerr ("Can't register AT-SPI focus change event listeners\n");
retval = 1;
goto out;
}
if (opt_keystroke &&
!client_enable_atspi_keystroke (client)) {
g_printerr ("Can't register AT-SPI keystroke event listeners\n");
retval = 1;
goto out;
}
} else {
g_printerr ("Desktop accessibility support is disabled\n");
retval = 1;
goto out;
}
}
#endif /* HAVE_ATSPI */
#ifdef HAVE_IBUS
if (focus == FOCUS_IBUS) {
ibus_init ();
if (!client_enable_ibus_focus (client)) {
g_printerr ("Can't register IBus focus change event listeners\n");
retval = 1;
goto out;
}
}
#endif /* HAVE_IBUS */
//#ifdef HAVE_XTEST
if (!client_enable_xtest (client)) {
g_printerr ("Can't init xtest\n");
g_object_unref (client);
exit (1);
}
//#endif /* HAVE_XTEST */
if (!opt_focus) {
g_object_get (client, "context", &context, NULL);
g_signal_connect (context, "destroyed",
G_CALLBACK(on_context_destroyed), NULL);
g_object_unref (context);
}
if (opt_fullscreen ||
g_settings_get_boolean (settings, "start-fullscreen")) {
g_object_get (client, "context", &context, NULL);
eekboard_context_set_fullscreen (context, TRUE, NULL);
g_object_unref (context);
}
g_object_get (client, "eekboard", &eekboard, NULL);
g_signal_connect (eekboard, "destroyed",
G_CALLBACK(on_destroyed), NULL);
g_object_unref (eekboard);
if (opt_keyboards != NULL) {
keyboards = g_strsplit (opt_keyboards, ",", -1);
if (!set_keyboards (client, (const gchar * const *)keyboards)) {
g_strfreev (keyboards);
retval = 1;
goto out;
}
g_strfreev (keyboards);
}
gtk_main ();
out:
if (client)
g_object_unref (client);
if (settings)
g_object_unref (settings);
return retval;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,55 +0,0 @@
/*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CLIENT_H
#define CLIENT_H 1
#include <gio/gio.h>
G_BEGIN_DECLS
#define TYPE_CLIENT (client_get_type())
#define CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_CLIENT, Client))
#define CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_CLIENT, ClientClass))
#define IS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_CLIENT))
#define IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_CLIENT))
#define CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_CLIENT, ClientClass))
typedef struct _Client SeatEmitter;
SeatEmitter *client_new (GDBusConnection *connection);
gboolean client_set_keyboards (SeatEmitter *client,
const gchar * const *keyboard);
gboolean client_enable_xkl (SeatEmitter *client);
void client_disable_xkl (SeatEmitter *client);
gboolean client_enable_atspi_focus (SeatEmitter *client);
void client_disable_atspi_focus (SeatEmitter *client);
gboolean client_enable_atspi_keystroke (SeatEmitter *client);
void client_disable_atspi_keystroke (SeatEmitter *client);
gboolean client_enable_xtest (SeatEmitter *client);
void client_disable_xtest (SeatEmitter *client);
gboolean client_enable_ibus_focus (SeatEmitter *client);
void client_disable_ibus_focus (SeatEmitter *client);
G_END_DECLS
#endif /* CLIENT_H */

4
src/config.h.in Normal file
View File

@ -0,0 +1,4 @@
/*
* Autogenerated by the Meson build system.
* Do not edit, your changes will be lost.
*/

View File

@ -5,11 +5,6 @@
#include "eekboard/eekboard-context-service.h" #include "eekboard/eekboard-context-service.h"
void imservice_handle_text_change_cause(void *data, struct zwp_input_method_v2 *input_method) {}
void imservice_handle_content_type(void *data, struct zwp_input_method_v2 *input_method) {}
void imservice_handle_unavailable(void *data, struct zwp_input_method_v2 *input_method) {}
static const struct zwp_input_method_v2_listener input_method_listener = { static const struct zwp_input_method_v2_listener input_method_listener = {
.activate = imservice_handle_input_method_activate, .activate = imservice_handle_input_method_activate,
.deactivate = imservice_handle_input_method_deactivate, .deactivate = imservice_handle_input_method_deactivate,
@ -25,19 +20,24 @@ struct imservice* get_imservice(EekboardContextService *context,
struct wl_seat *seat) { struct wl_seat *seat) {
struct zwp_input_method_v2 *im = zwp_input_method_manager_v2_get_input_method(manager, seat); struct zwp_input_method_v2 *im = zwp_input_method_manager_v2_get_input_method(manager, seat);
struct imservice *imservice = imservice_new(im, context); struct imservice *imservice = imservice_new(im, context);
zwp_input_method_v2_add_listener(im,
&input_method_listener, imservice); /* Add a listener, passing the imservice instance to make it available to
callbacks. */
zwp_input_method_v2_add_listener(im, &input_method_listener, imservice);
return imservice; return imservice;
} }
void imservice_make_visible(EekboardContextService *context, void imservice_make_visible(EekboardContextService *context) {
struct zwp_input_method_v2 *im) {
(void)im;
eekboard_context_service_show_keyboard (context); eekboard_context_service_show_keyboard (context);
} }
void imservice_try_hide(EekboardContextService *context, void imservice_try_hide(EekboardContextService *context) {
struct zwp_input_method_v2 *im) {
(void)im;
eekboard_context_service_hide_keyboard (context); eekboard_context_service_hide_keyboard (context);
} }
/// Declared explicitly because _destroy is inline,
/// making it unavailable in Rust
void imservice_destroy_im(struct zwp_input_method_v2 *im) {
zwp_input_method_v2_destroy(im);
}

View File

@ -18,5 +18,8 @@ void imservice_handle_input_method_deactivate(void *data, struct zwp_input_metho
void imservice_handle_surrounding_text(void *data, struct zwp_input_method_v2 *input_method, void imservice_handle_surrounding_text(void *data, struct zwp_input_method_v2 *input_method,
const char *text, uint32_t cursor, uint32_t anchor); const char *text, uint32_t cursor, uint32_t anchor);
void imservice_handle_commit_state(void *data, struct zwp_input_method_v2 *input_method); void imservice_handle_commit_state(void *data, struct zwp_input_method_v2 *input_method);
void imservice_handle_content_type(void *data, struct zwp_input_method_v2 *input_method, uint32_t hint, uint32_t purpose);
void imservice_handle_text_change_cause(void *data, struct zwp_input_method_v2 *input_method, uint32_t cause);
void imservice_handle_unavailable(void *data, struct zwp_input_method_v2 *input_method);
#endif #endif

View File

@ -3,6 +3,11 @@ use std::ffi::CString;
use std::num::Wrapping; use std::num::Wrapping;
use std::string::String; use std::string::String;
use super::bitflags;
// Traits
use std::convert::TryFrom;
/// Gathers stuff defined in C or called by C /// Gathers stuff defined in C or called by C
pub mod c { pub mod c {
@ -18,7 +23,7 @@ pub mod c {
} }
// The following defined in C // The following defined in C
/// struct zwp_input_method_v2* /// struct zwp_input_method_v2*
#[repr(transparent)] #[repr(transparent)]
pub struct InputMethod(*const c_void); pub struct InputMethod(*const c_void);
@ -29,8 +34,10 @@ pub mod c {
#[no_mangle] #[no_mangle]
extern "C" { extern "C" {
fn imservice_make_visible(imservice: *const UIManager); fn imservice_destroy_im(im: *mut c::InputMethod);
fn imservice_try_hide(imservice: *const UIManager); fn eekboard_context_service_set_hint_purpose(imservice: *const UIManager, hint: u32, purpose: u32);
fn eekboard_context_service_show_keyboard(imservice: *const UIManager);
fn eekboard_context_service_hide_keyboard(imservice: *const UIManager);
} }
// The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers // The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
@ -54,9 +61,9 @@ pub mod c {
#[no_mangle] #[no_mangle]
pub unsafe extern "C" pub unsafe extern "C"
fn imservice_handle_input_method_activate(imservice: *mut IMService, fn imservice_handle_input_method_activate(imservice: *mut IMService,
_im: *const InputMethod) im: *const InputMethod)
{ {
let imservice = &mut *imservice; let imservice = check_imservice(imservice, im).unwrap();
imservice.preedit_string = String::new(); imservice.preedit_string = String::new();
imservice.pending = IMProtocolState { imservice.pending = IMProtocolState {
active: true, active: true,
@ -67,9 +74,9 @@ pub mod c {
#[no_mangle] #[no_mangle]
pub unsafe extern "C" pub unsafe extern "C"
fn imservice_handle_input_method_deactivate(imservice: *mut IMService, fn imservice_handle_input_method_deactivate(imservice: *mut IMService,
_im: *const InputMethod) im: *const InputMethod)
{ {
let imservice = &mut *imservice; let imservice = check_imservice(imservice, im).unwrap();
imservice.pending = IMProtocolState { imservice.pending = IMProtocolState {
active: false, active: false,
..imservice.pending.clone() ..imservice.pending.clone()
@ -79,23 +86,65 @@ pub mod c {
#[no_mangle] #[no_mangle]
pub unsafe extern "C" pub unsafe extern "C"
fn imservice_handle_surrounding_text(imservice: *mut IMService, fn imservice_handle_surrounding_text(imservice: *mut IMService,
_im: *const InputMethod, im: *const InputMethod,
text: *const c_char, cursor: u32, _anchor: u32) text: *const c_char, cursor: u32, _anchor: u32)
{ {
let imservice = &mut *imservice; let imservice = check_imservice(imservice, im).unwrap();
imservice.pending = IMProtocolState { imservice.pending = IMProtocolState {
surrounding_text: into_cstring(text).expect("Received invalid string"), surrounding_text: into_cstring(text).expect("Received invalid string"),
surrounding_cursor: cursor, surrounding_cursor: cursor,
..imservice.pending ..imservice.pending.clone()
};
}
#[no_mangle]
pub unsafe extern "C"
fn imservice_handle_content_type(imservice: *mut IMService,
im: *const InputMethod,
hint: u32, purpose: u32)
{
let imservice = check_imservice(imservice, im).unwrap();
imservice.pending = IMProtocolState {
content_hint: {
ContentHint::from_bits(hint).unwrap_or_else(|| {
eprintln!("Warning: received invalid hint flags");
ContentHint::NONE
})
},
content_purpose: {
ContentPurpose::try_from(purpose).unwrap_or_else(|_e| {
eprintln!("Warning: Received invalid purpose value");
ContentPurpose::Normal
})
},
..imservice.pending.clone()
};
}
#[no_mangle]
pub unsafe extern "C"
fn imservice_handle_text_change_cause(imservice: *mut IMService,
im: *const InputMethod,
cause: u32)
{
let imservice = check_imservice(imservice, im).unwrap();
imservice.pending = IMProtocolState {
text_change_cause: {
ChangeCause::try_from(cause).unwrap_or_else(|_e| {
eprintln!("Warning: received invalid cause value");
ChangeCause::InputMethod
})
},
..imservice.pending.clone()
}; };
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" pub unsafe extern "C"
fn imservice_handle_commit_state(imservice: *mut IMService, fn imservice_handle_commit_state(imservice: *mut IMService,
_im: *const InputMethod) im: *const InputMethod)
{ {
let imservice = &mut *imservice; let imservice = check_imservice(imservice, im).unwrap();
let active_changed = imservice.current.active ^ imservice.pending.active; let active_changed = imservice.current.active ^ imservice.pending.active;
imservice.serial += Wrapping(1u32); imservice.serial += Wrapping(1u32);
@ -106,27 +155,174 @@ pub mod c {
}; };
if active_changed { if active_changed {
if imservice.current.active { if imservice.current.active {
imservice_make_visible(imservice.ui_manager); eekboard_context_service_show_keyboard(imservice.ui_manager);
eekboard_context_service_set_hint_purpose(
imservice.ui_manager,
imservice.current.content_hint.bits(),
imservice.current.content_purpose.clone() as u32);
} else { } else {
imservice_try_hide(imservice.ui_manager); eekboard_context_service_hide_keyboard(imservice.ui_manager);
} }
} }
} }
#[no_mangle]
pub unsafe extern "C"
fn imservice_handle_unavailable(imservice: *mut IMService,
im: *mut InputMethod)
{
let imservice = check_imservice(imservice, im).unwrap();
imservice_destroy_im(im);
// no need to care about proper double-buffering,
// the keyboard is already decommissioned
imservice.current.active = false;
eekboard_context_service_hide_keyboard(imservice.ui_manager);
}
// FIXME: destroy and deallocate // FIXME: destroy and deallocate
// Helpers
/// Convenience method for referencing the IMService raw pointer,
/// and for verifying that the input method passed along
/// matches the one in the `imservice`.
///
/// The lifetime of the returned value is 'static,
/// due to the fact that the lifetime of a raw pointer is undefined.
/// Care must be take
/// not to exceed the lifetime of the pointer with the reference,
/// especially not to store it.
fn check_imservice(imservice: *mut IMService, im: *const InputMethod)
-> Result<&'static mut IMService, &'static str>
{
if imservice.is_null() {
return Err("Null imservice pointer");
}
let imservice: &mut IMService = unsafe { &mut *imservice };
if im == imservice.im {
Ok(imservice)
} else {
Err("Imservice doesn't contain the input method")
}
}
}
bitflags!{
/// Map to `text_input_unstable_v3.content_hint` values
pub struct ContentHint: u32 {
const NONE = 0x0;
const COMPLETION = 0x1;
const SPELLCHECK = 0x2;
const AUTO_CAPITALIZATION = 0x4;
const LOWERCASE = 0x8;
const UPPERCASE = 0x10;
const TITLECASE = 0x20;
const HIDDEN_TEXT = 0x40;
const SENSITIVE_DATA = 0x80;
const LATIN = 0x100;
const MULTILINE = 0x200;
}
}
/// Map to `text_input_unstable_v3.content_purpose` values
///
/// ```
/// assert_eq!(ContentPurpose::Alpha as u32, 0);
/// ```
#[derive(Debug, Clone)]
pub enum ContentPurpose {
Normal = 0,
Alpha = 1,
Digits = 2,
Number = 3,
Phone = 4,
Url = 5,
Email = 6,
Name = 7,
Password = 8,
Pin = 9,
Date = 10,
Time = 11,
Datetime = 12,
Terminal = 13,
}
impl TryFrom<u32> for ContentPurpose {
// There's only one way to fail: number not in protocol,
// so no special error type is needed
type Error = ();
fn try_from(num: u32) -> Result<Self, Self::Error> {
use self::ContentPurpose::*;
match num {
0 => Ok(Normal),
1 => Ok(Alpha),
2 => Ok(Digits),
3 => Ok(Number),
4 => Ok(Phone),
5 => Ok(Url),
6 => Ok(Email),
7 => Ok(Name),
8 => Ok(Password),
9 => Ok(Pin),
10 => Ok(Date),
11 => Ok(Time),
12 => Ok(Datetime),
13 => Ok(Terminal),
_ => Err(()),
}
}
}
/// Map to `text_input_unstable_v3.change_cause` values
#[derive(Debug, Clone)]
pub enum ChangeCause {
InputMethod = 0,
Other = 1,
}
impl TryFrom<u32> for ChangeCause {
// There's only one way to fail: number not in protocol,
// so no special error type is needed
type Error = ();
fn try_from(num: u32) -> Result<Self, Self::Error> {
match num {
0 => Ok(ChangeCause::InputMethod),
1 => Ok(ChangeCause::Other),
_ => Err(())
}
}
} }
/// Describes the desired state of the input method as requested by the server /// Describes the desired state of the input method as requested by the server
#[derive(Default, Clone)] #[derive(Clone)]
struct IMProtocolState { struct IMProtocolState {
surrounding_text: CString, surrounding_text: CString,
surrounding_cursor: u32, surrounding_cursor: u32,
content_purpose: ContentPurpose,
content_hint: ContentHint,
text_change_cause: ChangeCause,
active: bool, active: bool,
} }
impl Default for IMProtocolState {
fn default() -> IMProtocolState {
IMProtocolState {
surrounding_text: CString::default(),
surrounding_cursor: 0, // TODO: mark that there's no cursor
content_hint: ContentHint::NONE,
content_purpose: ContentPurpose::Normal,
text_change_cause: ChangeCause::InputMethod,
active: false,
}
}
}
pub struct IMService { pub struct IMService {
/// Owned reference (still created and destroyed in C) /// Owned reference (still created and destroyed in C)
im: *const c::InputMethod, pub im: *const c::InputMethod,
/// Unowned reference. Be careful, it's shared with C at large /// Unowned reference. Be careful, it's shared with C at large
ui_manager: *const c::UIManager, ui_manager: *const c::UIManager,

4
src/lib.rs Normal file
View File

@ -0,0 +1,4 @@
#[macro_use]
mod bitflags;
mod imservice;

View File

@ -1,26 +1,24 @@
gnome = import('gnome') gnome = import('gnome')
dbus_src = gnome.gdbus_codegen( dbus_src = gnome.gdbus_codegen(
'sm.puri.OSK0', 'sm.puri.OSK0',
join_paths(dbusdir, 'sm.puri.OSK0.xml') join_paths(meson.source_root() / 'data' / 'dbus', 'sm.puri.OSK0.xml')
) )
squeek_enum_headers = [ config_h = configure_file(
'squeek-input-method.h', input: 'config.h.in',
] output: 'config.h',
configuration: conf_data
squeek_enums = gnome.mkenums_simple('squeek-enumtypes', sources: squeek_enum_headers) )
sources = [ sources = [
config_h,
'imservice.c', 'imservice.c',
'server-context-service.c', 'server-context-service.c',
'server-main.c',
'squeek-input-method.c',
'wayland.c', 'wayland.c',
'../eek/eek.c', '../eek/eek.c',
'../eek/eek-container.c', '../eek/eek-container.c',
'../eek/eek-element.c', '../eek/eek-element.c',
'../eek/eek-gtk-keyboard.c', '../eek/eek-gtk-keyboard.c',
'../eek/eek-gtk-renderer.c',
'../eek/eek-key.c', '../eek/eek-key.c',
'../eek/eek-keyboard.c', '../eek/eek-keyboard.c',
'../eek/eek-keyboard-drawing.c', '../eek/eek-keyboard-drawing.c',
@ -40,15 +38,14 @@ sources = [
'../eek/layersurface.c', '../eek/layersurface.c',
dbus_src, dbus_src,
enums, enums,
squeek_enums,
keysym_entries, keysym_entries,
marshalers, marshalers,
'../eekboard/keymap.c',
'../eekboard/key-emitter.c', '../eekboard/key-emitter.c',
'../eekboard/eekboard-context-service.c', '../eekboard/eekboard-context-service.c',
'../eekboard/eekboard-context.c', '../eekboard/eekboard-context.c',
'../eekboard/eekboard-service.c', '../eekboard/eekboard-service.c',
# '../eekboard/eekboard-xklutil.c', # '../eekboard/eekboard-xklutil.c',
squeekboard_resources,
wl_proto_sources, wl_proto_sources,
] ]
@ -72,15 +69,38 @@ deps = [
# Replacement for eekboard-server # Replacement for eekboard-server
rslib = static_library( rslib = static_library(
'rslib', 'rslib',
sources: ['imservice.rs'], sources: ['lib.rs'],
rust_crate_type: 'staticlib' rust_crate_type: 'staticlib'
) )
squeekboard = executable('squeekboard', rstests = executable(
'rstests',
sources: ['lib.rs'],
rust_args: ['--test'],
install: false
)
test('rstests', rstests)
libsqueekboard = static_library('libsqueekboard',
sources, sources,
link_with: rslib, link_with: rslib,
include_directories: [include_directories('..'), include_directories('../eek')], include_directories: [include_directories('..'), include_directories('../eek')],
dependencies: deps, dependencies: deps,
c_args: [
'-DTHEMESDIR="' + pkgdatadir + '/themes"',
'-DKEYBOARDSDIR="' + pkgdatadir + '/keyboards"',
'-DEEKBOARD_COMPILATION=1',
'-DEEK_COMPILATION=1'],
)
squeekboard = executable('squeekboard',
'server-main.c',
wl_proto_sources,
squeekboard_resources,
link_with: libsqueekboard,
include_directories: [include_directories('..'), include_directories('../eek')],
dependencies: deps,
install: true, install: true,
c_args: [ c_args: [
'-DTHEMESDIR="' + pkgdatadir + '/themes"', '-DTHEMESDIR="' + pkgdatadir + '/themes"',
@ -88,4 +108,3 @@ squeekboard = executable('squeekboard',
'-DEEKBOARD_COMPILATION=1', '-DEEKBOARD_COMPILATION=1',
'-DEEK_COMPILATION=1'], '-DEEK_COMPILATION=1'],
) )

View File

@ -1,415 +0,0 @@
/*
* Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2011 Red Hat, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include <gtk/gtk.h>
#include "preferences-dialog.h"
#include <eek/eek.h>
struct _PreferencesDialog {
GtkWidget *dialog;
GtkWidget *repeat_toggle;
GtkWidget *repeat_delay_scale;
GtkWidget *repeat_speed_scale;
GtkWidget *auto_hide_toggle;
GtkWidget *auto_hide_delay_scale;
GtkWidget *selected_keyboards_treeview;
GtkWidget *up_button;
GtkWidget *down_button;
GtkWidget *add_button;
GtkWidget *remove_button;
GtkWidget *new_keyboard_dialog;
GtkWidget *available_keyboards_treeview;
GList *available_keyboards;
GSettings *settings;
};
static gboolean
get_rate (GValue *value,
GVariant *variant,
gpointer user_data)
{
int rate;
gdouble fraction;
rate = g_variant_get_uint32 (variant);
fraction = 1.0 / ((gdouble) rate / 1000.0);
g_value_set_double (value, fraction);
return TRUE;
}
static GVariant *
set_rate (const GValue *value,
const GVariantType *expected_type,
gpointer user_data)
{
gdouble rate;
int msecs;
rate = g_value_get_double (value);
msecs = (1 / rate) * 1000;
return g_variant_new_uint32 (msecs);
}
static void
add_keyboard_to_treeview (GtkTreeView *treeview,
const gchar *id,
const gchar *longname)
{
GtkTreeModel *model = gtk_tree_view_get_model (treeview);
GtkTreeIter iter;
if (gtk_tree_model_get_iter_first (model, &iter)) {
do {
gchar *_id;
gtk_tree_model_get (model, &iter, 0, &_id, -1);
if (g_strcmp0 (id, _id) == 0) {
g_free (_id);
return;
}
g_free (_id);
} while (gtk_tree_model_iter_next (model, &iter));
}
gtk_list_store_append (GTK_LIST_STORE(model),
&iter);
gtk_list_store_set (GTK_LIST_STORE(model),
&iter,
0, id,
1, longname,
-1);
}
static void
add_keyboard (GtkWidget *button, PreferencesDialog *dialog)
{
gint retval = gtk_dialog_run (GTK_DIALOG(dialog->new_keyboard_dialog));
if (retval == GTK_RESPONSE_OK) {
GtkTreeSelection *selection;
GtkTreeModel *model;
GList *rows, *p;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(dialog->available_keyboards_treeview));
rows = gtk_tree_selection_get_selected_rows (selection, &model);
for (p = rows; p; p = p->next) {
GtkTreeIter iter;
if (gtk_tree_model_get_iter (model, &iter, p->data)) {
gchar *id, *longname;
gtk_tree_model_get (model, &iter, 0, &id, 1, &longname, -1);
add_keyboard_to_treeview (GTK_TREE_VIEW(dialog->selected_keyboards_treeview),
id,
longname);
g_free (id);
g_free (longname);
}
}
}
gtk_widget_hide (dialog->new_keyboard_dialog);
}
static void
remove_keyboard (GtkWidget *button, PreferencesDialog *dialog)
{
GtkTreeSelection *selection;
GtkTreeModel *model;
GList *rows, *p;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(dialog->selected_keyboards_treeview));
rows = gtk_tree_selection_get_selected_rows (selection, &model);
for (p = rows; p; p = p->next) {
GtkTreeIter iter;
if (gtk_tree_model_get_iter (model, &iter, p->data))
gtk_list_store_remove (GTK_LIST_STORE(model), &iter);
}
}
static void
up_keyboard (GtkWidget *button, PreferencesDialog *dialog)
{
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreeIter iter;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(dialog->selected_keyboards_treeview));
if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
GtkTreeIter prev = iter;
if (gtk_tree_model_iter_previous (model, &prev))
gtk_list_store_swap (GTK_LIST_STORE(model), &iter, &prev);
}
}
static void
down_keyboard (GtkWidget *button, PreferencesDialog *dialog)
{
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreeIter iter;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(dialog->selected_keyboards_treeview));
if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
GtkTreeIter next = iter;
if (gtk_tree_model_iter_next (model, &next))
gtk_list_store_swap (GTK_LIST_STORE(model), &iter, &next);
}
}
static void
selection_changed_cb (GtkTreeSelection *selection, PreferencesDialog *dialog)
{
gint count = gtk_tree_selection_count_selected_rows (selection);
if (count > 0) {
gtk_widget_set_sensitive (dialog->remove_button, TRUE);
gtk_widget_set_sensitive (dialog->up_button, TRUE);
gtk_widget_set_sensitive (dialog->down_button, TRUE);
} else {
gtk_widget_set_sensitive (dialog->remove_button, FALSE);
gtk_widget_set_sensitive (dialog->up_button, FALSE);
gtk_widget_set_sensitive (dialog->down_button, FALSE);
}
}
static gint
compare_keyboard_id (const EekXmlKeyboardDesc *desc, const char *id)
{
return g_strcmp0 (desc->id, id);
}
static void
populate_selected_keyboards (PreferencesDialog *dialog)
{
gchar **strv, **p;
strv = g_settings_get_strv (dialog->settings, "keyboards");
for (p = strv; *p != NULL; p++) {
GList *head = g_list_find_custom (dialog->available_keyboards,
*p,
(GCompareFunc) compare_keyboard_id);
if (head == NULL) {
g_warning ("unknown keyboard %s", *p);
} else {
EekXmlKeyboardDesc *desc = head->data;
add_keyboard_to_treeview (GTK_TREE_VIEW(dialog->selected_keyboards_treeview),
desc->id,
desc->longname);
}
}
g_strfreev (strv);
}
static void
populate_available_keyboards (PreferencesDialog *dialog)
{
GList *p;
for (p = dialog->available_keyboards; p; p = p->next) {
EekXmlKeyboardDesc *desc = p->data;
add_keyboard_to_treeview (GTK_TREE_VIEW(dialog->available_keyboards_treeview),
desc->id,
desc->longname);
}
}
static void
save_keyboards (PreferencesDialog *dialog)
{
GtkTreeModel *model;
GtkTreeIter iter;
GList *list = NULL, *head;
gchar **strv, **p;
model = gtk_tree_view_get_model (GTK_TREE_VIEW(dialog->selected_keyboards_treeview));
if (gtk_tree_model_get_iter_first (model, &iter)) {
do {
gchar *id;
gtk_tree_model_get (model, &iter, 0, &id, -1);
list = g_list_prepend (list, id);
} while (gtk_tree_model_iter_next (model, &iter));
}
list = g_list_reverse (list);
strv = g_new0 (gchar *, g_list_length (list) + 1);
for (head = list, p = strv; head; head = head->next, p++) {
*p = head->data;
}
g_settings_set_strv (dialog->settings,
"keyboards",
(const gchar * const *)strv);
g_strfreev (strv);
g_list_free (list);
}
PreferencesDialog *
preferences_dialog_new (void)
{
PreferencesDialog *dialog;
gchar *ui_path;
GtkBuilder *builder;
GObject *object;
GError *error;
GtkListStore *store;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
GtkTreeSelection *selection;
dialog = g_slice_new0 (PreferencesDialog);
dialog->settings = g_settings_new ("org.fedorahosted.eekboard");
builder = gtk_builder_new ();
gtk_builder_set_translation_domain (builder, "eekboard");
ui_path = g_build_filename (PKGDATADIR,
"preferences-dialog.ui",
NULL);
error = NULL;
if (gtk_builder_add_from_file (builder, ui_path, &error) == 0) {
g_warning ("can't load %s: %s", ui_path, error->message);
g_error_free (error);
}
g_free (ui_path);
object = gtk_builder_get_object (builder, "dialog");
dialog->dialog = GTK_WIDGET(object);
object = gtk_builder_get_object (builder, "repeat_toggle");
dialog->repeat_toggle = GTK_WIDGET(object);
g_settings_bind (dialog->settings, "repeat",
dialog->repeat_toggle, "active",
G_SETTINGS_BIND_DEFAULT);
object = gtk_builder_get_object (builder, "repeat_delay_scale");
dialog->repeat_delay_scale = GTK_WIDGET(object);
g_settings_bind (dialog->settings, "repeat-delay",
gtk_range_get_adjustment (GTK_RANGE (dialog->repeat_delay_scale)), "value",
G_SETTINGS_BIND_DEFAULT);
object = gtk_builder_get_object (builder, "repeat_speed_scale");
dialog->repeat_speed_scale = GTK_WIDGET(object);
g_settings_bind_with_mapping (dialog->settings, "repeat-interval",
gtk_range_get_adjustment (GTK_RANGE (gtk_builder_get_object (builder, "repeat_speed_scale"))), "value",
G_SETTINGS_BIND_DEFAULT,
get_rate, set_rate, NULL, NULL);
object = gtk_builder_get_object (builder, "auto_hide_toggle");
dialog->auto_hide_toggle = GTK_WIDGET(object);
g_settings_bind (dialog->settings, "auto-hide",
dialog->auto_hide_toggle, "active",
G_SETTINGS_BIND_DEFAULT);
object = gtk_builder_get_object (builder, "auto_hide_delay_scale");
dialog->auto_hide_delay_scale = GTK_WIDGET(object);
g_settings_bind (dialog->settings, "auto-hide-delay",
gtk_range_get_adjustment (GTK_RANGE (dialog->auto_hide_delay_scale)), "value",
G_SETTINGS_BIND_DEFAULT);
object = gtk_builder_get_object (builder,
"selected_keyboards_treeview");
dialog->selected_keyboards_treeview = GTK_WIDGET(object);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (object));
g_signal_connect (G_OBJECT(selection), "changed",
G_CALLBACK(selection_changed_cb), dialog);
renderer = GTK_CELL_RENDERER(gtk_cell_renderer_text_new ());
column = gtk_tree_view_column_new_with_attributes ("Keyboard",
renderer,
"text",
1,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (object), column);
object = gtk_builder_get_object (builder, "up_button");
dialog->up_button = GTK_WIDGET(object);
g_signal_connect (object, "clicked",
G_CALLBACK(up_keyboard), dialog);
object = gtk_builder_get_object (builder, "down_button");
dialog->down_button = GTK_WIDGET(object);
g_signal_connect (object, "clicked",
G_CALLBACK(down_keyboard), dialog);
object = gtk_builder_get_object (builder, "add_button");
dialog->add_button = GTK_WIDGET(object);
g_signal_connect (object, "clicked",
G_CALLBACK(add_keyboard), dialog);
object = gtk_builder_get_object (builder, "remove_button");
dialog->remove_button = GTK_WIDGET(object);
g_signal_connect (object, "clicked",
G_CALLBACK(remove_keyboard), dialog);
object = gtk_builder_get_object (builder, "new_keyboard_dialog");
dialog->new_keyboard_dialog = GTK_WIDGET(object);
object = gtk_builder_get_object (builder,
"available_keyboards_treeview");
dialog->available_keyboards_treeview = GTK_WIDGET(object);
renderer = GTK_CELL_RENDERER(gtk_cell_renderer_text_new ());
column = gtk_tree_view_column_new_with_attributes ("Keyboard",
renderer,
"text",
1,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (object), column);
object = gtk_builder_get_object (builder,
"available_keyboards_liststore");
store = GTK_LIST_STORE(object);
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(store),
1,
GTK_SORT_ASCENDING);
dialog->available_keyboards = eek_xml_list_keyboards ();
populate_selected_keyboards (dialog);
populate_available_keyboards (dialog);
g_object_unref (builder);
return dialog;
}
void
preferences_dialog_run (PreferencesDialog *dialog)
{
gtk_window_present (GTK_WINDOW(dialog->dialog));
gtk_dialog_run (GTK_DIALOG(dialog->dialog));
save_keyboards (dialog);
}
void
preferences_dialog_free (PreferencesDialog *dialog)
{
gtk_widget_destroy (dialog->dialog);
// gtk_widget_destroy (dialog->new_keyboard_dialog);
g_object_unref (dialog->settings);
g_list_free_full (dialog->available_keyboards,
(GDestroyNotify) eek_xml_keyboard_desc_free);
g_slice_free (PreferencesDialog, dialog);
}

View File

@ -1,32 +0,0 @@
/*
* Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2011 Red Hat, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PREFERENCES_DIALOG_H
#define PREFERENCES_DIALOG_H 1
#include <glib-object.h>
G_BEGIN_DECLS
typedef struct _PreferencesDialog PreferencesDialog;
PreferencesDialog *preferences_dialog_new (void);
void preferences_dialog_run (PreferencesDialog *dialog);
void preferences_dialog_free (PreferencesDialog *dialog);
G_END_DECLS
#endif /* PREFERENCES_DIALOG_H */

View File

@ -1,729 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkAction" id="action1">
<property name="stock_id">gtk-close</property>
</object>
<object class="GtkAction" id="action2">
<property name="stock_id">gtk-cancel</property>
</object>
<object class="GtkAction" id="action3">
<property name="label" translatable="yes">Select</property>
<property name="stock_id">gtk-ok</property>
</object>
<object class="GtkAdjustment" id="auto_hide_delay_adjustment">
<property name="lower">100</property>
<property name="upper">2000</property>
<property name="value">500</property>
<property name="step_increment">10</property>
<property name="page_increment">10</property>
</object>
<object class="GtkListStore" id="available_keyboards_liststore">
<columns>
<!-- column-name id -->
<column type="gchararray"/>
<!-- column-name gchararray1 -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkDialog" id="dialog">
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Keyboard</property>
<property name="modal">True</property>
<property name="type_hint">dialog</property>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="dialog-action_area5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<object class="GtkButton" id="button1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="related_action">action1</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkNotebook" id="keyboard_notebook">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="border_width">10</property>
<child>
<object class="GtkVBox" id="general_page">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">12</property>
<property name="spacing">18</property>
<child>
<object class="GtkVBox" id="vbox22">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel" id="label300">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Repeat Keys</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="hbox19">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="label43">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label"> </property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkVBox" id="vbox100">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkCheckButton" id="repeat_toggle">
<property name="label" translatable="yes">Key presses _repeat when key is held down</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkTable" id="repeat_table">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="n_rows">2</property>
<property name="n_columns">4</property>
<child>
<object class="GtkLabel" id="repeat_speed_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">_Speed:</property>
<property name="use_underline">True</property>
<property name="justify">center</property>
<property name="mnemonic_widget">repeat_speed_scale</property>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_SHRINK</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="delay_short_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="xpad">10</property>
<property name="label" translatable="yes">Short</property>
<attributes>
<attribute name="style" value="italic"/>
<attribute name="scale" value="0.82999999999999996"/>
</attributes>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="x_options">GTK_SHRINK</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="repeat_slow_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="xpad">10</property>
<property name="label" translatable="yes">Slow</property>
<attributes>
<attribute name="style" value="italic"/>
<attribute name="scale" value="0.82999999999999996"/>
</attributes>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_SHRINK</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkHScale" id="repeat_delay_scale">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">repeat_delay_adjustment</property>
<property name="draw_value">False</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkHScale" id="repeat_speed_scale">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">repeat_speed_adjustment</property>
<property name="draw_value">False</property>
<child internal-child="accessible">
<object class="AtkObject" id="repeat_speed_scale-atkobject">
<property name="AtkObject::accessible-description" translatable="yes">Repeat keys speed</property>
</object>
</child>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="delay_long_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Long</property>
<attributes>
<attribute name="style" value="italic"/>
<attribute name="scale" value="0.82999999999999996"/>
</attributes>
</object>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="x_options">GTK_SHRINK</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="repeat_fast_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Fast</property>
<attributes>
<attribute name="style" value="italic"/>
<attribute name="scale" value="0.82999999999999996"/>
</attributes>
</object>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_SHRINK</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="repeat_delay_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">_Delay:</property>
<property name="use_underline">True</property>
<property name="justify">center</property>
<property name="mnemonic_widget">repeat_delay_scale</property>
</object>
<packing>
<property name="x_options">GTK_SHRINK</property>
<property name="y_options"></property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkVBox" id="vbox230">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Focus following</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="hbox20">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="label44">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label"> </property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkVBox" id="appearances_vbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkCheckButton" id="auto_hide_toggle">
<property name="label" translatable="yes">Auto hide window when focus is out</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="n_columns">4</property>
<child>
<object class="GtkLabel" id="auto_hide_delay_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">_Delay:</property>
<property name="use_underline">True</property>
<property name="justify">center</property>
<property name="mnemonic_widget">auto_hide_delay_scale</property>
</object>
<packing>
<property name="x_options">GTK_SHRINK</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="auto_hide_delay_short_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="xpad">10</property>
<property name="label" translatable="yes">Short</property>
<attributes>
<attribute name="style" value="italic"/>
<attribute name="scale" value="0.82999999999999996"/>
</attributes>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="x_options">GTK_SHRINK</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkHScale" id="auto_hide_delay_scale">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">auto_hide_delay_adjustment</property>
<property name="draw_value">False</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="auto_hide_delay_long_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Long</property>
<attributes>
<attribute name="style" value="italic"/>
<attribute name="scale" value="0.82999999999999996"/>
</attributes>
</object>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="x_options">GTK_SHRINK</property>
<property name="y_options"></property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<child type="tab">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Typing</property>
</object>
<packing>
<property name="tab_fill">False</property>
</packing>
</child>
<child>
<object class="GtkVBox" id="keyboards_page">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">12</property>
<property name="spacing">18</property>
<child>
<object class="GtkTreeView" id="selected_keyboards_treeview">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">selected_keyboards_liststore</property>
<property name="headers_visible">False</property>
<property name="headers_clickable">False</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection2"/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButtonBox" id="buttonbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="up_button">
<property name="label">gtk-go-up</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="down_button">
<property name="label">gtk-go-down</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="add_button">
<property name="label">gtk-add</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="remove_button">
<property name="label">gtk-remove</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child type="tab">
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Keyboards</property>
</object>
<packing>
<property name="position">1</property>
<property name="tab_fill">False</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child type="tab">
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="0">button1</action-widget>
</action-widgets>
</object>
<object class="GtkDialog" id="new_keyboard_dialog">
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="default_height">430</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">dialog</property>
<property name="transient_for">dialog</property>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox2">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="dialog-action_area2">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="button2">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="related_action">action2</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button3">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="related_action">action3</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="available_keyboards_treeview">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">available_keyboards_liststore</property>
<property name="headers_visible">False</property>
<property name="headers_clickable">False</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection3"/>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="0">button2</action-widget>
<action-widget response="-5">button3</action-widget>
</action-widgets>
</object>
<object class="GtkAdjustment" id="repeat_delay_adjustment">
<property name="lower">100</property>
<property name="upper">2000</property>
<property name="value">500</property>
<property name="step_increment">10</property>
<property name="page_increment">10</property>
</object>
<object class="GtkAdjustment" id="repeat_speed_adjustment">
<property name="lower">0.5</property>
<property name="upper">50</property>
<property name="value">33.299999999999997</property>
<property name="step_increment">1</property>
<property name="page_increment">1</property>
</object>
<object class="GtkListStore" id="selected_keyboards_liststore">
<columns>
<!-- column-name id -->
<column type="gchararray"/>
<!-- column-name gchararray1 -->
<column type="gchararray"/>
</columns>
</object>
</interface>

View File

@ -1,7 +1,7 @@
/* /*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org> * Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc. * Copyright (C) 2010-2011 Red Hat, Inc.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
@ -15,15 +15,11 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <glib/gi18n.h> #include <glib/gi18n.h>
#include <gdk/gdkx.h>
#include "eek/eek-gtk.h" #include "eek/eek-gtk.h"
#include "eek/layersurface.h" #include "eek/layersurface.h"
#include "wayland.h" #include "wayland.h"
@ -42,13 +38,9 @@ typedef struct _ServerContextServiceClass ServerContextServiceClass;
struct _ServerContextService { struct _ServerContextService {
EekboardContextService parent; EekboardContextService parent;
gboolean was_visible;
GtkWidget *window; GtkWidget *window;
GtkWidget *widget; GtkWidget *widget;
gulong notify_visible_handler;
gdouble size_constraint_landscape[2]; gdouble size_constraint_landscape[2];
gdouble size_constraint_portrait[2]; gdouble size_constraint_portrait[2];
}; };
@ -59,16 +51,13 @@ struct _ServerContextServiceClass {
G_DEFINE_TYPE (ServerContextService, server_context_service, EEKBOARD_TYPE_CONTEXT_SERVICE); G_DEFINE_TYPE (ServerContextService, server_context_service, EEKBOARD_TYPE_CONTEXT_SERVICE);
static void update_widget (ServerContextService *context);
static void set_geometry (ServerContextService *context); static void set_geometry (ServerContextService *context);
static void set_dock (GtkWidget *widget,
GtkAllocation *allocation);
static void static void
on_monitors_changed (GdkScreen *screen, on_monitors_changed (GdkScreen *screen,
gpointer user_data) ServerContextService *context)
{ {
ServerContextService *context = user_data;
if (context->window) if (context->window)
set_geometry (context); set_geometry (context);
} }
@ -87,18 +76,19 @@ on_destroy (GtkWidget *widget, gpointer user_data)
} }
static void static void
on_notify_keyboard (GObject *object, make_widget (ServerContextService *context);
GParamSpec *spec,
gpointer user_data) static void
on_notify_keyboard (GObject *object,
GParamSpec *spec,
ServerContextService *context)
{ {
ServerContextService *context = user_data;
const EekKeyboard *keyboard; const EekKeyboard *keyboard;
keyboard = eekboard_context_service_get_keyboard (EEKBOARD_CONTEXT_SERVICE(context)); keyboard = eekboard_context_service_get_keyboard (EEKBOARD_CONTEXT_SERVICE(context));
if (!keyboard) { if (!keyboard)
g_error("Programmer error: keyboard layout was unset!"); g_error("Programmer error: keyboard layout was unset!");
}
// The keymap will get set even if the window is hidden. // The keymap will get set even if the window is hidden.
// It's not perfect, // It's not perfect,
@ -106,146 +96,68 @@ on_notify_keyboard (GObject *object,
eekboard_context_service_set_keymap(EEKBOARD_CONTEXT_SERVICE(context), eekboard_context_service_set_keymap(EEKBOARD_CONTEXT_SERVICE(context),
keyboard); keyboard);
if (context->window) { /* Recreate the keyboard widget to keep in sync with the keymap. */
if (keyboard == NULL) { if (context->window)
gtk_widget_hide (context->window); make_widget(context);
gtk_widget_destroy (context->widget);
context->widget = NULL; gboolean visible;
} else { g_object_get (context, "visible", &visible, NULL);
gboolean was_visible = gtk_widget_get_visible (context->window);
/* avoid to send KeyboardVisibilityChanged */ if (visible) {
g_signal_handler_block (context->window, eekboard_context_service_hide_keyboard(EEKBOARD_CONTEXT_SERVICE(context));
context->notify_visible_handler); eekboard_context_service_show_keyboard(EEKBOARD_CONTEXT_SERVICE(context));
update_widget (context);
if (was_visible) {
gtk_widget_show_all (context->window);
}
g_signal_handler_unblock (context->window,
context->notify_visible_handler);
}
} }
} }
static void static void
on_notify_fullscreen (GObject *object, on_notify_fullscreen (GObject *object,
GParamSpec *spec, GParamSpec *spec,
gpointer user_data) ServerContextService *context)
{ {
ServerContextService *context = user_data;
if (context->window) if (context->window)
set_geometry (context); set_geometry (context);
} }
static void static void
on_notify_visible (GObject *object, GParamSpec *spec, gpointer user_data) on_notify_map (GObject *object,
ServerContextService *context)
{ {
ServerContextService *context = user_data; g_object_set (context, "visible", TRUE, NULL);
gboolean visible;
g_object_get (object, "visible", &visible, NULL);
g_object_set (context, "visible", visible, NULL);
} }
static void static void
set_dock (GtkWidget *widget, GtkAllocation *allocation) on_notify_unmap (GObject *object,
ServerContextService *context)
{ {
#ifdef HAVE_XDOCK g_object_set (context, "visible", FALSE, NULL);
GdkWindow *window = gtk_widget_get_window (widget);
long vals[12];
/* set window type to dock */
gdk_window_set_type_hint (window, GDK_WINDOW_TYPE_HINT_DOCK);
vals[0] = 0;
vals[1] = 0;
vals[2] = 0;
vals[3] = allocation->height;
vals[4] = 0;
vals[5] = 0;
vals[6] = 0;
vals[7] = 0;
vals[8] = 0;
vals[9] = 0;
vals[10] = allocation->x;
vals[11] = allocation->x + allocation->width;
XChangeProperty (GDK_WINDOW_XDISPLAY (window),
GDK_WINDOW_XID (window),
XInternAtom (GDK_WINDOW_XDISPLAY (window),
"_NET_WM_STRUT_PARTIAL", False),
XA_CARDINAL, 32, PropModeReplace,
(guchar *)vals, 12);
#endif /* HAVE_XDOCK */
} }
static void
on_realize_set_dock (GtkWidget *widget,
gpointer user_data)
{
GtkAllocation allocation;
gtk_widget_get_allocation (widget, &allocation);
set_dock (widget, &allocation);
}
static void
on_size_allocate_set_dock (GtkWidget *widget,
GdkRectangle *allocation,
gpointer user_data)
{
if (gtk_widget_get_realized (widget))
set_dock (widget, allocation);
}
static void
on_realize_set_non_maximizable (GtkWidget *widget,
gpointer user_data)
{
ServerContextService *context = user_data;
g_assert (context && context->window == widget);
/* make the window not maximizable */
gdk_window_set_functions (gtk_widget_get_window (widget),
GDK_FUNC_RESIZE |
GDK_FUNC_MOVE |
GDK_FUNC_MINIMIZE |
GDK_FUNC_CLOSE);
}
static void static void
set_geometry (ServerContextService *context) set_geometry (ServerContextService *context)
{ {
GdkScreen *screen; GdkScreen *screen = gdk_screen_get_default ();
GdkWindow *root; GdkWindow *root = gdk_screen_get_root_window (screen);
gint monitor; GdkDisplay *display = gdk_display_get_default ();
GdkMonitor *monitor = gdk_display_get_monitor_at_window (display, root);
EekKeyboard *keyboard = eekboard_context_service_get_keyboard (EEKBOARD_CONTEXT_SERVICE(context));
GdkRectangle rect; GdkRectangle rect;
const EekKeyboard *keyboard;
EekBounds bounds; EekBounds bounds;
screen = gdk_screen_get_default (); gdk_monitor_get_geometry (monitor, &rect);
root = gtk_widget_get_root_window (context->window);
monitor = gdk_screen_get_monitor_at_window (screen, root);
gdk_screen_get_monitor_geometry (screen, monitor, &rect);
keyboard = eekboard_context_service_get_keyboard (EEKBOARD_CONTEXT_SERVICE(context));
eek_element_get_bounds (EEK_ELEMENT(keyboard), &bounds); eek_element_get_bounds (EEK_ELEMENT(keyboard), &bounds);
g_signal_handlers_disconnect_by_func (context->window,
on_realize_set_dock,
context);
g_signal_handlers_disconnect_by_func (context->window,
on_realize_set_non_maximizable,
context);
if (eekboard_context_service_get_fullscreen (EEKBOARD_CONTEXT_SERVICE(context))) { if (eekboard_context_service_get_fullscreen (EEKBOARD_CONTEXT_SERVICE(context))) {
gint width = rect.width; gint width = rect.width;
gint height = rect.height; gint height = rect.height;
if (width > height) { if (width > height) {
width *= context->size_constraint_landscape[0]; width *= context->size_constraint_landscape[0];
height *= context->size_constraint_landscape[1]; height *= context->size_constraint_landscape[1];
} else { } else {
width *= context->size_constraint_portrait[0]; width *= context->size_constraint_portrait[0];
height *= context->size_constraint_portrait[1]; height *= context->size_constraint_portrait[1];
} }
@ -262,50 +174,36 @@ set_geometry (ServerContextService *context)
gtk_window_set_decorated (GTK_WINDOW(context->window), FALSE); gtk_window_set_decorated (GTK_WINDOW(context->window), FALSE);
gtk_window_set_resizable (GTK_WINDOW(context->window), FALSE); gtk_window_set_resizable (GTK_WINDOW(context->window), FALSE);
g_signal_connect_after (context->window, "realize",
G_CALLBACK(on_realize_set_dock),
context);
g_signal_connect_after (context->window, "size-allocate",
G_CALLBACK(on_size_allocate_set_dock),
context);
} else {
gtk_window_resize (GTK_WINDOW(context->window),
bounds.width,
bounds.height);
gtk_window_move (GTK_WINDOW(context->window),
MAX(rect.width - 20 - bounds.width, 0),
MAX(rect.height - 40 - bounds.height, 0));
g_signal_connect_after (context->window, "realize",
G_CALLBACK(on_realize_set_non_maximizable),
context);
} }
} }
#define KEYBOARD_HEIGHT 210
static void static void
make_window (ServerContextService *context) { make_window (ServerContextService *context)
if (context->window) { {
if (context->window)
g_error("Window already present"); g_error("Window already present");
return;
} context->window = g_object_new (
context->window = GTK_WIDGET(g_object_new (
PHOSH_TYPE_LAYER_SURFACE, PHOSH_TYPE_LAYER_SURFACE,
"layer-shell", squeek_wayland->layer_shell, "layer-shell", squeek_wayland->layer_shell,
"wl-output", g_ptr_array_index(squeek_wayland->outputs, 0), // TODO: select output as needed, "wl-output", g_ptr_array_index(squeek_wayland->outputs, 0), // TODO: select output as needed,
"height", 200, "height", KEYBOARD_HEIGHT,
"anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM "anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM
| ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
| ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT,
"layer", ZWLR_LAYER_SHELL_V1_LAYER_TOP, "layer", ZWLR_LAYER_SHELL_V1_LAYER_TOP,
"kbd-interactivity", FALSE, "kbd-interactivity", FALSE,
"exclusive-zone", 200, "exclusive-zone", KEYBOARD_HEIGHT,
//"namespace", "phosh home", "namespace", "osk",
NULL NULL
)); );
g_signal_connect (context->window, "destroy",
G_CALLBACK(on_destroy), context); g_object_connect (context->window,
context->notify_visible_handler = "signal::destroy", G_CALLBACK(on_destroy), context,
g_signal_connect (context->window, "notify::visible", "signal::map", G_CALLBACK(on_notify_map), context,
G_CALLBACK(on_notify_visible), context); "signal::unmap", G_CALLBACK(on_notify_unmap), context,
NULL);
// The properties below are just to make hacking easier. // The properties below are just to make hacking easier.
// The way we use layer-shell overrides some, // The way we use layer-shell overrides some,
@ -321,36 +219,37 @@ make_window (ServerContextService *context) {
} }
static void static void
destroy_window (ServerContextService *context) { destroy_window (ServerContextService *context)
{
gtk_widget_destroy (GTK_WIDGET (context->window));
context->window = NULL; context->window = NULL;
} }
static void static void
update_widget (ServerContextService *context) make_widget (ServerContextService *context)
{ {
EekKeyboard *keyboard; EekKeyboard *keyboard;
EekBounds bounds;
gchar *theme_path;
EekTheme *theme; EekTheme *theme;
if (context->widget) { if (context->widget) {
gtk_widget_destroy (context->widget); gtk_widget_destroy(context->widget);
context->widget = NULL; context->widget = NULL;
} }
theme_path = g_build_filename (THEMESDIR, "default.css", NULL); theme = eek_theme_new ("resource:///sm/puri/squeekboard/style.css",
NULL,
theme = eek_theme_new (theme_path, NULL, NULL); NULL);
g_free (theme_path);
keyboard = eekboard_context_service_get_keyboard (EEKBOARD_CONTEXT_SERVICE(context)); keyboard = eekboard_context_service_get_keyboard (EEKBOARD_CONTEXT_SERVICE(context));
eek_element_get_bounds (EEK_ELEMENT(keyboard), &bounds);
context->widget = eek_gtk_keyboard_new (keyboard); context->widget = eek_gtk_keyboard_new (keyboard);
eek_gtk_keyboard_set_theme (EEK_GTK_KEYBOARD(context->widget), theme); eek_gtk_keyboard_set_theme (EEK_GTK_KEYBOARD(context->widget), theme);
g_object_unref (theme); g_clear_object (&theme);
gtk_widget_set_has_tooltip (context->widget, TRUE); gtk_widget_set_has_tooltip (context->widget, TRUE);
gtk_container_add (GTK_CONTAINER(context->window), context->widget); gtk_container_add (GTK_CONTAINER(context->window), context->widget);
gtk_widget_show (context->widget);
set_geometry (context); set_geometry (context);
} }
@ -359,11 +258,14 @@ server_context_service_real_show_keyboard (EekboardContextService *_context)
{ {
ServerContextService *context = SERVER_CONTEXT_SERVICE(_context); ServerContextService *context = SERVER_CONTEXT_SERVICE(_context);
make_window (context); if (!context->window)
update_widget (context); make_window (context);
if (!context->widget)
make_widget (context);
EEKBOARD_CONTEXT_SERVICE_CLASS (server_context_service_parent_class)-> EEKBOARD_CONTEXT_SERVICE_CLASS (server_context_service_parent_class)->
show_keyboard (_context); show_keyboard (_context);
gtk_widget_show (context->window);
} }
static void static void
@ -372,34 +274,11 @@ server_context_service_real_hide_keyboard (EekboardContextService *_context)
ServerContextService *context = SERVER_CONTEXT_SERVICE(_context); ServerContextService *context = SERVER_CONTEXT_SERVICE(_context);
gtk_widget_hide (context->window); gtk_widget_hide (context->window);
gtk_container_remove(GTK_CONTAINER(context->window), context->widget);
destroy_window (context);
EEKBOARD_CONTEXT_SERVICE_CLASS (server_context_service_parent_class)-> EEKBOARD_CONTEXT_SERVICE_CLASS (server_context_service_parent_class)->
hide_keyboard (_context); hide_keyboard (_context);
} }
static void
server_context_service_real_enabled (EekboardContextService *_context)
{
ServerContextService *context = SERVER_CONTEXT_SERVICE(_context);
if (context->was_visible && context->window)
gtk_widget_show_all (context->window);
}
static void
server_context_service_real_disabled (EekboardContextService *_context)
{
ServerContextService *context = SERVER_CONTEXT_SERVICE(_context);
if (context->window) {
context->was_visible =
gtk_widget_get_visible (context->window);
gtk_widget_hide (context->window);
}
}
static void static void
server_context_service_real_destroyed (EekboardContextService *_context) server_context_service_real_destroyed (EekboardContextService *_context)
{ {
@ -439,10 +318,8 @@ server_context_service_dispose (GObject *object)
{ {
ServerContextService *context = SERVER_CONTEXT_SERVICE(object); ServerContextService *context = SERVER_CONTEXT_SERVICE(object);
if (context->window) { destroy_window (context);
gtk_widget_destroy (context->window); context->widget = NULL;
context->window = NULL;
}
G_OBJECT_CLASS (server_context_service_parent_class)->dispose (object); G_OBJECT_CLASS (server_context_service_parent_class)->dispose (object);
} }
@ -456,8 +333,6 @@ server_context_service_class_init (ServerContextServiceClass *klass)
context_class->show_keyboard = server_context_service_real_show_keyboard; context_class->show_keyboard = server_context_service_real_show_keyboard;
context_class->hide_keyboard = server_context_service_real_hide_keyboard; context_class->hide_keyboard = server_context_service_real_hide_keyboard;
context_class->enabled = server_context_service_real_enabled;
context_class->disabled = server_context_service_real_disabled;
context_class->destroyed = server_context_service_real_destroyed; context_class->destroyed = server_context_service_real_destroyed;
gobject_class->set_property = server_context_service_set_property; gobject_class->set_property = server_context_service_set_property;
@ -487,9 +362,8 @@ server_context_service_class_init (ServerContextServiceClass *klass)
static void static void
server_context_service_init (ServerContextService *context) server_context_service_init (ServerContextService *context)
{ {
GdkScreen *screen; GdkScreen *screen = gdk_screen_get_default ();
screen = gdk_screen_get_default ();
g_signal_connect (screen, g_signal_connect (screen,
"monitors-changed", "monitors-changed",
G_CALLBACK(on_monitors_changed), G_CALLBACK(on_monitors_changed),
@ -498,6 +372,7 @@ server_context_service_init (ServerContextService *context)
"notify::keyboard", "notify::keyboard",
G_CALLBACK(on_notify_keyboard), G_CALLBACK(on_notify_keyboard),
context); context);
g_signal_connect (context, g_signal_connect (context,
"notify::fullscreen", "notify::fullscreen",
G_CALLBACK(on_notify_fullscreen), G_CALLBACK(on_notify_fullscreen),
@ -507,6 +382,5 @@ server_context_service_init (ServerContextService *context)
EekboardContextService * EekboardContextService *
server_context_service_new () server_context_service_new ()
{ {
return EEKBOARD_CONTEXT_SERVICE(g_object_new (SERVER_TYPE_CONTEXT_SERVICE, return EEKBOARD_CONTEXT_SERVICE(g_object_new (SERVER_TYPE_CONTEXT_SERVICE, NULL));
NULL));
} }

Some files were not shown because too many files have changed in this diff Show More